I am trying to make a trait usable on top-level functions in Rust.
trait FnTrait {
fn call(self);
}
impl FnTrait for fn() {
fn call(self) {
self()
}
}
fn foo() {
println!("Hello, World!")
}
fn main() {
FnTrait::call(foo)
}
However the code below fails to compile with (Playground Link)
error[E0277]: the trait bound `fn() {foo}: FnTrait` is not satisfied
--> <anon>:16:5
|
16 | FnTrait::call(foo)
| ^^^^^^^^^^^^^ the trait `FnTrait` is not implemented for `fn() {foo}`
|
= help: the following implementations were found:
<fn() as FnTrait>
= note: required by `FnTrait::call`
I found I can trick it into compiling by casting foo like so
FnTrait::call(foo as fn())
But it is annoying and some of the functions in my program are more complicated than foo. Any way to avoid the cast? Is my trait wrong somehow?
Every function in Rust has its own type. As you can see, foo isn't a fn(), it's a fn() {foo}; sadly, this is not an actual type you can write in source, that's just a compiler message thing. The distinction exists to make it easier for the compiler to let you pass around functions as values whilst still being able to inline the calls.
The consequence is that named functions pointers cannot be turned into general function pointers without either a cast or a type hint. For example, this works:
fn foo() {
println!("Hello, World!")
}
fn bar(f: fn()) {
f()
}
fn main() {
bar(foo)
}
However, I'm not aware of any way to leverage this to get the trait to work.
The only way forward is to stop trying to implement the trait for function pointers, and instead implement it for everything callable:
trait FnTrait {
fn call(self);
}
impl<F> FnTrait for F where F: FnOnce() {
fn call(self) {
self()
}
}
fn foo() {
println!("Hello, World!")
}
fn main() {
foo.call();
}
(Semi-relevant answer about the difference between Fn, FnMut and FnOnce.)
This will work for anything that's callable with that signature, including both functions and closures. The downside is that you can only have one such implementation. You can't implement this trait for any other signature.
One generic implementation, or many specific implementations and lots of manual casting. Pick your poison.
As an aside: there's no such thing as a "top level function" in Rust, at least not as a thing distinct from other kinds of functions. Functions are functions, no matter where they appear. Instance functions a.k.a. methods are still regular functions, it's just that their first argument is called "self".
Related
In the example below the Default trait is used just for demonstration purposes.
My questions are:
What is the difference between the declarations of f() and g()?
Why g() doesn't compile since it's identical to f()?
How can I return a concrete type out of a impl trait generically typed declaration?
struct Something {
}
impl Default for Something {
fn default() -> Self {
Something{}
}
}
// This compiles.
pub fn f() -> impl Default {
Something{}
}
// This doesn't.
pub fn g<T: Default>() -> T {
Something{}
}
What is the difference between the declarations of f() and g()?
f returns some type which implements Default. The caller of f has no say in what type it will return.
g returns some type which implements Default. The caller of g gets to pick the exact type that must be returned.
You can clearly see this difference in how f and g can be called. For example:
fn main() {
let t = f(); // this is the only way to call f()
let t = g::<i32>(); // I can call g() like this
let t = g::<String>(); // or like this
let t = g::<Vec<Box<u8>>(); // or like this... and so on!
// there's potentially infinitely many ways I can call g()
// and yet there is only 1 way I can call f()
}
Why g() doesn't compile since it's identical to f()?
They're not identical. The implementation for f compiles because it can only be called in 1 way and it will always return the exact same type. The implementation for g fails to compile because it can get called infinitely many ways for all different types but it will always return Something which is broken.
How can I return a concrete type out of a impl trait generically typed declaration?
If I'm understanding your question correctly, you can't. When you use generics you let the caller decide the types your function must use, so your function's implementation itself must be generic. If you want to construct and return a generic type within a generic function the usual way to go about that is to put a Default trait bound on the generic type and use that within your implementation:
// now works!
fn g<T: Default>() -> T {
T::default()
}
If you need to conditionally select the concrete type within the function then the only other solution is to return a trait object:
struct Something;
struct SomethingElse;
trait Trait {}
impl Trait for Something {}
impl Trait for SomethingElse {}
fn g(some_condition: bool) -> Box<dyn Trait> {
if some_condition {
Box::new(Something)
} else {
Box::new(SomethingElse)
}
}
how can I return a concrete type out of a "impl trait" generically typed declaration?
By "impl trait" generically typed declaration I presume you mean "impl trait" rewritten to use named generics. However, that's a false premise - impl Trait in return position was introduced precisely because you can't express it using named generics. To see this, consider first impl Trait in argument position, such as this function:
fn foo(iter: impl Iterator<Item = u32>) -> usize {
iter.count()
}
You can rewrite that function to use named generics as follows:
fn foo<I: Iterator<Item = u32>>(iter: I) -> usize {
iter.count()
}
Barring minor technical differences, the two are equivalent. However, if impl Trait is in return position, such as here:
fn foo() -> impl Iterator<Item = u32> {
vec![1, 2, 3].into_iter()
}
...you cannot rewrite it to use generics without losing generality. For example, this won't compile:
fn foo<T: Iterator<Item = u32>>() -> T {
vec![1, 2, 3].into_iter()
}
...because, as explained by pretzelhammer, the signature promises the caller the ability to choose which type to return (out of those that implement Iterator<Item = u32>), but the implementation only ever returns a concrete type, <Vec<u32> as IntoIterator>::IntoIter.
On the other hand, this does compile:
fn foo() -> <Vec<u32> as IntoIterator>::IntoIter {
vec![1, 2, 3].into_iter()
}
...but now the generality is lost because foo() must be implemented as a combination of Vec and into_iter() - even adding a map() in between the two would break it.
This also compiles:
fn foo() -> Box<dyn Iterator<Item = u32>> {
Box::new(vec![1, 2, 3].into_iter())
}
...but at the cost of allocating the iterator on the heap and disabling some optimizations.
I am trying to write a function that takes a slice of functions. Consider the following simple illustration:
fn g<P: Fn(&str) -> usize>(ps: &[P]) { }
fn f1() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn f2() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn main() {
g(&[f1(), f2()][..]);
}
It fails to compile:
error[E0308]: mismatched types
--> src/main.rs:6:15
|
6 | g(&[f1(), f2()][..]);
| ^^^^ expected opaque type, found a different opaque type
|
= note: expected type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
found type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
Is there any way to do this?
Your problem is that every element of the array must be of the same type, but the return of a function declared as returning impl Trait is an opaque type, that is an unspecified, unnamed type, that you can only use by means of the given trait.
You have two functions that return the same impl Trait but that does not mean that they return the same type. In fact, as your compiler shows, they are different opaque types, so they cannot be part of the same array. If you were to write an array of values of the same type, such as:
g(&[f1(), f1(), f1()]);
then it would work. But with different functions, there will be different types and the array is impossible to build.
Does that mean there is no solution for your problem? Of course not! You just have to invoke dynamic dispatch. That is you have to make your slice of type &[&dyn Fn(&str) -> usize]. For that you need to do two things:
Add a level of indirection: dynamic dispatching is always done via references or pointers (&dyn Trait or Box<dyn Trait> instead of Trait).
Do an explicit cast to the &dyn Trait to avoid ambiguities in the conversion.
There are many ways to do the cast: you can cast the first element of the array, or you can declare the temporary variables, or give the slice a type. I prefer the latter, because it is more symmetric. Something like this:
fn main() {
let fns: &[&dyn Fn(&str) -> usize] =
&[&f1(), &f2()];
g(fns);
}
Link to a playground with this solution.
My understanding was that objects created outside of the scope are available inside the scope (hence things such as shadowing allowed), but it does not seem to work in this scenario:
extern crate csv;
extern crate rand;
use rand::Rng;
use std::path::Path;
use std::time::SystemTime;
#[derive(Debug)]
struct Event {
time: SystemTime,
value: u32,
}
impl Event {
fn new(t: SystemTime, n: u32) -> Event {
Event {
time: SystemTime,
value: n,
}
}
}
struct Process;
impl Process {
fn new() -> Process {
Process {}
}
fn start(&self) {
loop {
let now = SystemTime::now();
let random_number: u32 = rand::thread_rng().gen();
let event = Event::new(now, random_number);
self.callback(event);
}
}
fn callback(&self, event: Event) {
println!("{:?}", event);
wtr.write_record(&event).unwrap();
wtr.flush().unwrap();
}
}
fn main() {
let file_path = Path::new("test.csv");
let mut wtr = csv::Writer::from_path(file_path).unwrap();
let process: Process = Process::new();
process.start();
}
The errors are:
error[E0423]: expected value, found struct `SystemTime`
--> src/main.rs:17:19
|
17 | time: SystemTime,
| ^^^^^^^^^^ constructor is not visible here due to private fields
error[E0425]: cannot find value `wtr` in this scope
--> src/main.rs:41:9
|
41 | wtr.write_record(&event).unwrap();
| ^^^ not found in this scope
error[E0425]: cannot find value `wtr` in this scope
--> src/main.rs:42:9
|
42 | wtr.flush().unwrap();
| ^^^ not found in this scope
How can I append data (Event) to a CSV file from inside the callback function for Process?
I strongly encourage you to go back and re-read The Rust Programming Language, specifically the chapter about functions. This code appears to show fundamental issues around the entire model of how functions work.
For example, the code attempts to make use of the variable wtr in the function callback without it being passed in either directly or indirectly.
If such code worked1, programmers would likely hate dealing with this language because it would be almost impossible to tell what and where the value wtr even came from.
The solution is straightforward: pass any value that a piece of code needs to that code. Then it's easy (or easier) to tell where the value came from. There are multiple avenues that can work.
Pass an argument to the callback method:
use std::io::Write;
impl Process {
fn start<R>(&self, wtr: &mut csv::Writer<R>)
where
R: Write,
{
loop {
// ...
self.callback(wtr, event);
}
}
fn callback<R>(&self, wtr: &mut csv::Writer<R>, event: Event)
where
R: Write,
{
// ...
}
}
fn main() {
// ...
process.start(&mut wtr);
}
Pass an argument to the constructor and save it inside the struct:
use std::io::Write;
struct Process<'a, R>
where
R: Write + 'a,
{
wtr: &'a mut csv::Writer<R>,
}
impl<'a, R> Process<'a, R>
where
R: Write,
{
fn new(wtr: &'a mut csv::Writer<R>) -> Self {
Process { wtr }
}
// ...
fn callback(&self, event: Event) {
// ...
self.wtr.write_record(event).unwrap();
self.wtr.flush().unwrap();
}
}
fn main() {
// ...
let process = Process::new(&mut wtr);
}
The code has other issues in how it uses the CSV library that I'm ignoring because they are unrelated to your question. I encourage you to start with a simpler piece of code, get it working, then make it more complex. That way you are only dealing with simpler errors at first.
Once you understand this basic usage of functions, you may wish to learn about closures. These allow you to "capture" variables from an outer scope and pass them in (in the same two methods as above) without having to deal with the specific count or type of variables.
objects created outside of the scope are available inside the scope
This is true for a single function. It does not apply across functions.
hence things such as shadowing allowed
Shadowing has nothing to to with scopes. You are allowed to shadow inside the same scope:
let a = Some(32);
let a = a.unwrap();
1. Such languages exist; they are languages with dynamic scope and some people prefer them. They are in the minority, programs written in these languages are hard to reason about!
In one of my structs Struct1 there's a field of type time::Tm. Somewhere in the code an instance of the struct gets decoded from a json string to an instance of Struct1.
json::decode(&maybe_struct1)
At first I got an error saying that to_json isn't implemented for time::Tm. So I implemented it:
impl json::ToJson for time::Tm {
fn to_json(&self) -> json::Json {
let mut d = BTreeMap::new();
d.insert("tm_sec".to_string(), self.tm_sec.to_json());
d.insert("tm_min".to_string(), self.tm_min.to_json());
//..............
And now it says
error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
I gathered that it was a bug before version 1. But it is still? If not how do I fix it?
It's not a bug - it is feature. Really. To implement trait any of this statements must be true:
type is declared in this module
trait is declared in this module
otherwise you get E0117. You can find more info using rustc --explain E0117:
This error indicates a violation of one of Rust's orphan rules for trait implementations. The rule prohibits any implementation of a foreign trait (atrait defined in another crate) where
the type that is implementing the trait is foreign
all of the parameters being passed to the trait (if there are any) are also foreign.
Here's one example of this error:
impl Drop for u32 {}
To avoid this kind of error, ensure that at least one local type is referencedby the impl:
pub struct Foo; // you define your type in your crate
impl Drop for Foo { // and you can implement the trait on it!
// code of trait implementation here
}
impl From<Foo> for i32 { // or you use a type from your crate as
// a type parameter
fn from(i: Foo) -> i32 { 0 }
}
Alternatively, define a trait locally and implement that instead:
trait Bar {
fn get(&self) -> usize;
}
impl Bar for u32 {
fn get(&self) -> usize { 0 }
}
For information on the design of the orphan rules, see RFC 1023.
EDIT:
To achieve what you want you have 2 solutions:
implement ToJson on your whole type:
impl json::ToJson for Struct1 { … }
create a wrapper type struct TmWrapper(time::Tm); and implement 2 traits for it From and ToJson.
EDIT 2:
Step by step explonation:
This is what you want to achieve: http://is.gd/6UF3jd
Solutions:
implement trait on whole type using types that you want: http://is.gd/CRfPeJ
create wrapper type and implement trait that you want on it: http://is.gd/7XV5w9
This is exactly what is described in explanation of the error code above.
So you see - at least one of trait or struct must be declare within current unit to allow implementation of trait on given type. In your case both of them are external types and that is what is Rust preventing. If you want to achieve something like that you need to use some hacks as described above.
It's not a bug. The language requires when you implement a trait that you defined either the trait or the type involved. If you implemented neither, it doesn't allow it.
If it didn't, it would be possible for someone else to come along and also implement json::ToJson for time::Tm, and suddenly the compiler has no idea which code to use.
The simplest way to work around this is to wrap your time::Tm in a newtype, like so:
struct TmWrap(time::Tm);
Now, because you defined this type, you can implement json::ToJson on it. This does mean you have to wrap/unwrap the Tm constantly, but the only other alternative is to implement ToJson for the entire containing Struct1 type, which is probably going to be even more work.
I just ran into a problem with how Rust handles closures.
Let's assume I'm a library author and have written this method
fn get(&mut self, handler: fn() -> &str){
//do something with handler
}
Now if a user wants to call this method like this
let foo = "str";
server.get(|| -> &str { foo });
It won't work because Rust, according to it's documentation makes a strong difference between regular functions and closures.
Do I as a library author always have to make such methods accept closures instead of regular functions to not restrict library users too much?
Also it seems to me as if closures are the only way to write anonymous functions or am I mistaken?
Currently, fn() types can be automatically "promoted" to || types. (A closure with an empty environment, I suppose.) For example, this works:
fn get(handler: || -> &str) -> &str {
handler()
}
fn main() {
fn handler_fn() -> &str { "handler_fn" }
let handler_cl = || -> &str "handler_cl";
println!("{}", get(handler_fn));
println!("{}", get(handler_cl));
}
So if your library function get doesn't care whether handler is a closure or not, then it seems reasonable to just accept closures for maximum flexibility. But this isn't always possible. For example, if you wanted to execute handler in another task, then I believe it must be a fn or a proc type. (I'm not 100% certain here---I may be missing a detail.)
With regard to anonymous functions, yes, a || or a proc closure are the only two ways to write anonymous functions.