A bit of a beginner Rust question - say I have the following code, which compiles:
trait XGetter {
fn get_x(&self) -> i32;
}
struct Foo {
x: i32
}
impl XGetter for Foo {
fn get_x(&self) -> i32 {
self.x
}
}
struct Bar<'a>(&'a dyn XGetter);
impl<'a> XGetter for Bar<'a> {
fn get_x(&self) -> i32 {
self.0.get_x()
}
}
fn baz() -> i32 {
let foo = Foo { x: 42 };
let bar = Bar(&foo);
bar.get_x()
}
Let's say I want to extract out the creation of Bar, in order encapsulate the creation of the XGetter and Bar together, such that baz() now reads:
fn baz2() -> i32 {
let bar = createBar(42);
bar.get_x()
}
However, by implementing createBar below, I run a-fowl of the borrow checker:
fn createBar<'a>(x: i32) -> Bar<'a> {
let foo = Foo { x };
let bar = Bar(&foo);
// ---- `foo` is borrowed here
bar
// ^^^ returns a value referencing data owned by the current function
}
How would one extract out a function createBar which doesn't break the borrowing rules?
The foo in createBar() dies when the function ends, so the bar you return would be pointing to invalid memory.
Given how you have written the call to createBar(42), it looks like you want Bar to own the Foo, so do that:
struct Bar(Box<dyn XGetter>);
impl XGetter for Bar {
fn get_x(&self) -> i32 {
self.0.get_x()
}
}
fn createBar(x: i32) -> Bar {
let foo = Box::new(Foo { x });
let bar = Bar(foo);
bar
}
You can not:
The signature struct Bar<'a>(&'a dyn XGetter); and createBar(i: 32) are incompatible. Because it means that in createBar you would have to instantiate an object implementing XGetter and that reference will not live outside of the scope of createBar.
fn createBar<'a>(x: i32) -> Bar<'a> {
let foo = Foo { x };
let bar = Bar(&foo);
// ---- `foo` is borrowed here
bar
// ^^^ returns a value referencing data owned by the current function
}
^^^ That means that the variable foo will live just during createBar scope.
That said, you could use:
fn createBar(g: &dyn XGetter) -> Bar<'_> {
Bar(g)
}
That way the reference will live outside of the scope of createBar.
Playground
As per the comments. If you want to abstract that, you need Bar to own Foo
struct Bar(Box<dyn XGetter>);
fn createBar(x: i32) -> Bar {
let foo = Box::new(Foo { x });
let bar = Bar(foo);
bar
}
Related
I'm a newbie with Rust and I bumped into some obstacles when dealing with closures, either when returning them from functions and or methods, either when I need to store them as struct fields.
Let's start with what is working:
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo<F>
where
F: Fn(usize) -> usize,
{
fn new(foo: F) -> Self {
Self { foo }
}
}
fn main() {
let foo1 = Foo { foo: |a| a + 1 };
let foo2 = Foo { foo: build_func(2) };
let foo_func = build_func(3);
let foo3 = Foo { foo: foo_func };
}
This works as expected and the type of the closure that is built outside the struct is properly matched with the generic of Foo.
I wanted to achieve the same, but by hiding the creation of the closure simply by moving it inside the impl of Foo itself.
I tested these alternatives, but none of theme compiles:
struct Foo2<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
struct Foo3<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo3<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = |a| a + 1;
Self { foo }
}
}
struct Foo4<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo4<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> F {
move |a| a + b
}
}
struct Foo5<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo5<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
I understand that each closure has its own opaque and distinct type, but then I don't understand why on the other hand the initial implementation of Foo works then.
By reading the accepted answer here I seem to understand that the only option, in this case, would be to box the closure, but I still don't have a full understanding.
By combining boxed closure and trait aliases (I know it's not the "real" trait aliasing) I came up with this:
trait Func: Fn(usize) -> usize {}
impl<T> Func for T where T: Fn(usize) -> usize {}
struct Foo6 {
pub foo: Box<dyn Func>,
}
impl Foo6 {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Func {
move |a| a + b
}
}
fn main() {
let foo = Foo6::new();
println!("{}", (foo.foo)(1));
}
But I'm wondering whether it's possible to obtain an unboxed version.
The problem in this code:
impl<F> Foo2<F>
where
F: Fn(usize) -> usize,
{
fn new() -> Self {
let foo = build_func(1);
Self { foo }
}
}
is that to call it, the user code would need to write something like this:
let foo2 = <Foo2<?>>::new();
And specify some type there. Even if the type is not typed explicitly, it should be resolved there (type omission is mostly syntactic sugar). But the type of the stored value is decided inside that function, in the call to build_func(1), so the user has no type to use there and that function cannot be called.
My advice is to just write a free function:
fn new_foo2() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
Now the generic type is an impl in the return type of the function, that is an special opaque generic decided by the code of the function. So this works.
If you really, really want to write Foo2::new you can write the function implementation inside a dummy non-generic impl Foo2 block. Usually that would be impl Foo2<()> but the type () does not satisfies your constraints, but you can use any other dummy type that does:
impl Foo2<fn(usize)->usize> {
fn new() -> Foo2<impl Fn(usize) -> usize> {
let foo = build_func(1);
Foo2 { foo }
}
}
(Note that this new() does not return Self because the generic type is not correct.)
And now you can at least write:
let foo2 = Foo2::new();
The difference here is that you're returning Self from new(). Inside impl<F> Foo<F>, Self refers to Foo<F>. And F is a generic parameter - you cannot build a closure of type F, because it's a type your caller decides what it is, not you.
Your first version works because it tells the compiler "I will return some type implementing Fn; I'll leave it to you infer what exactly". On the other hand, the second versions are all "given any type F implementing Fn, I'll give you an instance of that type". That is of course impossible.
Instead you want the compiler to infer the used type here, too. The best solution will be to use impl Trait here, too. But impl Trait in positions other than return type is unstable. It will look like (playground):
#![feature(type_alias_impl_trait)]
type InnerFn = impl Fn(usize) -> usize;
struct Foo {
pub foo: InnerFn,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo }
}
fn build_func(b: usize) -> InnerFn {
move |a| a + b
}
}
Another (quite hacky) solution is to have a generic parameter, but not use it and instead use impl Trait in new(). To not require the caller to specify the redundant parameter (since it can't be inferred anymore as it's unused), we can use a marker type, usually (). This requires us to remove the F: Fn(usize) -> usize bound from the struct and put it only on the impl, however this is a good style anyway (playground):
struct Foo<F> {
pub foo: F,
}
impl Foo<()> {
fn new() -> Foo<impl Fn(usize) -> usize> {
let foo = Self::build_func(1);
Foo { foo }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
The last solution is indeed to box the closure, but you don't need a new trait for that - you can use Fn directly (playground):
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
impl Foo {
fn new() -> Self {
let foo = Self::build_func(1);
Self { foo: Box::new(foo) }
}
fn build_func(b: usize) -> impl Fn(usize) -> usize {
move |a| a + b
}
}
I'm trying to recreate a simple callback pattern in Rust using 2 structs. One will pass a bit of logic to execute whenever the other one is ready. The issue here is that the logic will run only if a certain value from the struct is true.
I can understand why the reference to Foo needs to live for 'static in this case, but I'm not sure how to refactor so that it compiles.
Seems like a pretty regular use case, but maybe I'm missing something since I'm new to Rust.
struct Foo {
value: bool,
}
struct Bar {
closure: Box<dyn Fn() -> ()>,
}
impl Foo {
fn new() -> Self {
Foo {
value: false,
}
}
fn set_closure(&self, b: &mut Bar) {
b.closure = self.get_closure();
}
fn get_closure(&self) -> Box<dyn Fn() -> ()> {
return Box::new(|| {
if self.value {
println!("true");
} else {
println!("false");
}
});
}
}
impl Bar {
fn new() -> Self {
Bar {
closure: Box::new(|| {})
}
}
}
fn main() {
let foo = Foo::new();
let mut bar = Bar::new();
foo.set_closure(&mut bar);
let closure = bar.closure;
closure();
}
Playground link -> here
You need to move the value into the closure:
fn get_closure(&self) -> Box<dyn Fn() -> ()> {
let value = self.value;
Box::new(move || {
if value {
println!("true");
} else {
println!("false");
}
})
}
Notice that in your example value is a bool which is Copy. If not you can either capture a reference or clone it. (If capturing a reference you may need to adjust some lifetimes there).
Playground
Suppose I have the following type:
#[derive(Default)]
struct Foo(pub i32); // public
Since it's a tuple with a public member, any conversions from/to i32 can simply be made using the 0 member:
let foo = Foo::default();
let num: i32 = foo.0; // Foo to i32
let goo = Foo(123); // i32 to Foo
Now I want to make the 0 member non-public, implementing From trait:
#[derive(Default)]
struct Foo(i32); // non-public
impl From<i32> for Foo {
fn from(n: i32) -> Foo {
Foo(n)
}
}
But the conversion fails from i32 to Foo:
let foo = ay::Foo::default();
let num: i32 = foo.into(); // error!
let goo = ay::Foo::from(123); // okay
What's the correct way to implement this bidirectional conversion? Rust playground here.
You have to implement the other direction (impl From<Foo> for i32) manually:
mod x {
#[derive(Default)]
pub struct Foo(i32);
impl From<i32> for Foo {
fn from(n: i32) -> Foo {
Foo(n)
}
}
impl From<Foo> for i32 {
fn from(foo: Foo) -> i32 {
foo.0
}
}
}
fn main() {
let foo = x::Foo::default();
let _num: i32 = foo.into(); // okay
let _goo = x::Foo::from(123); // also okay
}
You can test this in the playground
Before Rust 1.0, I could write a structure using this obsolete closure syntax:
struct Foo {
pub foo: |usize| -> usize,
}
Now I can do something like:
struct Foo<F: FnMut(usize) -> usize> {
pub foo: F,
}
But then what's the type of a Foo object I create?
let foo: Foo<???> = Foo { foo: |x| x + 1 };
I could also use a reference:
struct Foo<'a> {
pub foo: &'a mut FnMut(usize) -> usize,
}
I think this is slower because
the pointer dereference
there's no specialization for the type of FnMut that actually ends up being used
Complementing the existing answer with some more code for demonstration purposes:
Unboxed closure
Use a generic type:
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo<F>
where
F: Fn(usize) -> usize,
{
fn new(foo: F) -> Self {
Self { foo }
}
}
fn main() {
let foo = Foo { foo: |a| a + 1 };
(foo.foo)(42);
(Foo::new(|a| a + 1).foo)(42);
}
Boxed trait object
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
impl Foo {
fn new(foo: impl Fn(usize) -> usize + 'static) -> Self {
Self { foo: Box::new(foo) }
}
}
fn main() {
let foo = Foo {
foo: Box::new(|a| a + 1),
};
(foo.foo)(42);
(Foo::new(|a| a + 1).foo)(42);
}
Trait object reference
struct Foo<'a> {
pub foo: &'a dyn Fn(usize) -> usize,
}
impl<'a> Foo<'a> {
fn new(foo: &'a dyn Fn(usize) -> usize) -> Self {
Self { foo }
}
}
fn main() {
let foo = Foo { foo: &|a| a + 1 };
(foo.foo)(42);
(Foo::new(&|a| a + 1).foo)(42);
}
Function pointer
struct Foo {
pub foo: fn(usize) -> usize,
}
impl Foo {
fn new(foo: fn(usize) -> usize) -> Self {
Self { foo }
}
}
fn main() {
let foo = Foo { foo: |a| a + 1 };
(foo.foo)(42);
(Foo::new(|a| a + 1).foo)(42);
}
what's the type of a Foo object I create?
It's an unnameable, automatically generated type.
I could also use a reference [...] slower because [...] the pointer deref [...] no specialization
Perhaps, but it can be much easier on the caller.
See also:
How do I call a function through a member variable?
Returning a closure from a function
How to return an anonymous type from a trait method without using Box?
Closures as a type in a Rust struct
Types of unboxed closures being unique to each
Why does passing a closure to function which accepts a function pointer not work?
What does "dyn" mean in a type?
For what type you'd use in your third code snippet, there isn't one; closure types are anonymous and cannot be directly named. Instead, you'd write:
let foo = Foo { foo: |x| x + 1 };
If you're writing code in a context where you need to specify that you want a Foo, you'd write:
let foo: Foo<_> = Foo { foo: |x| x + 1 };
The _ tells the type system to infer the actual generic type for you.
The general rule of thumb as to which to use, in descending order:
Generic parameters: struct Foo<F: FnMut(usize) -> usize>. This is the most efficient, but it does mean that a specific Foo instance can only ever store one closure, since every closure has a different concrete type.
Trait references: &'a mut dyn FnMut(usize) -> usize. There's a pointer indirection, but now you can store a reference to any closure that has a compatible call signature.
Boxed closures: Box<dyn FnMut(usize) -> usize>. This involves allocating the closure on the heap, but you don't have to worry about lifetimes. As with a reference, you can store any closure with a compatible signature.
Before Rust 1.0
Closures that used the || syntax were references to closures stored on the stack, making them equivalent to &'a mut FnMut(usize) -> usize. Old-style procs were heap-allocated and were equivalent to Box<dyn FnOnce(usize) -> usize> (you can only call a proc once).
I'm not sure how to properly title this post. I'm fairly new to Rust and trying to compile a program following this simple structure, but it seems to be incorrect, and I'm not sure why.
struct Bar;
impl Bar {
fn do_thing(&self) { println!("Ha, do nothing!") }
}
struct Foo<'a> {
bar: &'a Bar
}
impl<'a> Foo<'a> {
fn new(b: &Bar) -> Foo { Foo { bar: b } }
fn get_bar(&self) -> &Bar { self.bar }
}
fn main() {
let b = Bar;
let b_ref = {
let f = Foo::new(&b);
f.get_bar()
};
b_ref.do_thing();
}
The compiler error here claims that f does not live long enough. It shouldn't matter how long f lives though -- b_ref is valid for as long as b is, and I thought that references were Copy so that we wouldn't have to worry about the actual reference in f. Is this relevant?
Part of me feels like I need to specify the lifetime of the &Bar being returned from get_bar, but I don't know how to tie that into the lifetime of the Foo struct?
What am I missing here?
You have to specify that the reference you are returning is tied to the lifetime 'a and not the lifetime of self that compiler will infer for you:
impl<'a> Foo<'a> {
fn new(b: &Bar) -> Foo { Foo { bar: b } }
fn get_bar(&self) -> &'a Bar { self.bar }
}
This is equivalent to the original code:
impl<'a> Foo<'a> {
fn new(b: &Bar) -> Foo { Foo { bar: b } }
fn get_bar<'b>(&'b self) -> &'b Bar { self.bar }
}
Part of me feel like I should need to specify the lifetime of the &Bar
being returned from get_bar, but I don't know how to tie that into the
lifetime of the Foo struct?
The lifetime of Foo does not matter at all in this case.