How to call a method through a function pointer? [duplicate] - methods

This question already has an answer here:
Is there a way to create a function pointer to a method in Rust?
(1 answer)
Closed 3 years ago.
What is the correct syntax to call a method on an object using a function pointer?
struct Foo {
var: i32,
}
impl Foo {
fn method(&mut self, arg: i32) {
self.var = self.var + arg;
println!("var = {}", self.var);
}
}
fn main() {
let foo = Foo { var: 11 };
let func_ptr: Fn() = &foo.method;
(func_ptr).method(12);
}
I am getting this error:
error[E0615]: attempted to take value of method `method` on type `Foo`
--> src/main.rs:14:31
|
14 | let func_ptr: Fn() = &foo.method;
| ^^^^^^ help: use parentheses to call the method: `method(...)`
error[E0599]: no method named `method` found for type `dyn std::ops::Fn()` in the current scope
--> src/main.rs:15:16
|
15 | (func_ptr).method(12);
| ^^^^^^
|
= note: (func_ptr) is a function, perhaps you wish to call it
error[E0277]: the size for values of type `dyn std::ops::Fn()` cannot be known at compilation time
--> src/main.rs:14:9
|
14 | let func_ptr: Fn() = &foo.method;
| ^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn std::ops::Fn()`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: all local variables must have a statically known size
= help: unsized locals are gated as an unstable feature
I guess I am not using correct type for func_ptr type; what is the correct type?

Methods do not bind the self argument, but you can get access to the methods via their fully qualified names and you can save them in a function pointer if you like. Later on, when you invoke the function pointer you have to provide the self argument yourself:
struct Foo {
var: i32,
}
impl Foo {
fn method(&mut self, value: i32) {
self.var += value;
println!("var = {}", self.var);
}
}
fn main() {
let mut foo = Foo { var: 11 };
let func_ptr = Foo::method;
func_ptr(&mut foo, 12);
}
If you'd like to manually define the type of this local variable then it would be the following:
let func_ptr: fn(&mut Foo, i32) = Foo::method;
If you'd like to use the trait notation, you have to use it behind a reference:
let func_ptr: &Fn(&mut Foo, i32) = &Foo::method;

Related

How can I pass a method as a function parameter? [duplicate]

For example,
struct Foo;
impl Foo {
fn bar(&self) {}
fn baz(&self) {}
}
fn main() {
let foo = Foo;
let callback = foo.bar;
}
error[E0615]: attempted to take value of method `bar` on type `Foo`
--> src/main.rs:10:24
|
10 | let callback = foo.bar;
| ^^^ help: use parentheses to call the method: `bar()`
With fully-qualified syntax, Foo::bar will work, yielding a fn(&Foo) -> () (similar to Python).
let callback = Foo::bar;
// called like
callback(&foo);
However, if you want it with the self variable already bound (as in, calling callback() will be the same as calling bar on the foo object), then you need to use an explicit closure:
let callback = || foo.bar();
// called like
callback();

Is it possible to unpack a tuple into method arguments?

Unpacking a tuple as arguments and calling a function with those values is covered by Is it possible to unpack a tuple into function arguments?, but is it possible to do the same trick on methods?
#![feature(fn_traits)]
struct Foo;
impl Foo {
fn method(&self, a: i32, b: i32) {
println!("{:?}, {:?}", a, b);
}
}
fn main() {
let foo = Foo;
let tuple = (10, 42);
// does not compile
//foo.method.call(tuple);
// nor this one
//std::ops::Fn::call(&foo.method, tuple);
}
For both I get the following error:
error[E0615]: attempted to take value of method `method` on type `Foo`
--> src/main.rs:20:9
|
20 | foo.method.call(tuple);
| ^^^^^^ help: use parentheses to call the method: `method(...)`
I do not control the method I call, so changing the signature to accept tuples is not an option.
Methods are functions that
Are associated with a type (called associated functions). Most people are familiar with "constructor" associated functions like new. These are referenced as Type::function_name.
Take some kind of Self as the first argument.
Thus you need to use Foo::method and provide a matching self:
#![feature(fn_traits)]
struct Foo;
impl Foo {
fn method(&self, a: i32, b: i32) {
println!("{:?}, {:?}", a, b);
}
}
fn main() {
let foo = Foo;
let tuple = (&foo, 10, 42);
std::ops::Fn::call(&Foo::method, tuple);
}
See also:
Fully-qualified syntax
What types are valid for the `self` parameter of a method?

How do I convert a mutable reference to self into an immutable reference to be used as an argument for a method?

I have following code that can't be compiled:
struct A {
x: i32,
}
impl A {
fn add_assign(&mut self, other: &Self) {
self.x += other.x;
}
fn double(&mut self) {
self.add_assign(self);
}
}
The error is:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/lib.rs:11:9
|
11 | self.add_assign(self);
| ^^^^^----------^----^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
How to pass self as the argument of add_assign? I have tried &self, *self, &*self without success.
For the current version of the question
fn add_assign(&mut self, other: &Self)
Your request is impossible.
You cannot have a mutable reference and an immutable reference to the same value at the same time. This is a fundamental aspect of Rust.
Please re-read the rules of references.
See also:
Cannot borrow as mutable because it is also borrowed as immutable
For the first version of the question
fn add_assign(&mut self, other: Self)
Your request is impossible.
You need one instance of struct A to call the method on and another instance of A to pass as the argument. Your type does not implement Copy or Clone or provide any equivalent methods so there is no way to get a second instance.
Beyond that, there's no universal way to take a mutable reference to a value and get an owned value out of it.
See also:
Cannot move out of borrowed content / cannot move out of behind a shared reference
Workarounds
If you implement Copy or Clone, then you can get a second value from the original and then call either of your versions.
If you implemented Copy:
(other: Self)
self.add_assign(*self);
(other: &Self)
let other = *self;
self.add_assign(&other);
If only Clone:
(other: Self)
self.add_assign(self.clone());
(other: &Self)
self.add_assign(&self.clone());
You probably want to implement the AddAssign trait to provide syntax sugar. Assuming you've implemented Copy:
impl A {
fn double(&mut self) {
*self += *self;
}
}
impl std::ops::AddAssign<Self> for A {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
}
}
Stargateur's comment may also be applicable, as i32 implements Copy:
impl A {
fn double(&mut self) {
*self += self.x;
}
}
impl std::ops::AddAssign<i32> for A {
fn add_assign(&mut self, other: i32) {
self.x += other;
}
}

Borrow mutable and immutable reference in the same block [duplicate]

Why does the call self.f2() in the following code trip the borrow checker? Isn't the else block in a different scope? This is quite a conundrum!
use std::str::Chars;
struct A;
impl A {
fn f2(&mut self) {}
fn f1(&mut self) -> Option<Chars> {
None
}
fn f3(&mut self) {
if let Some(x) = self.f1() {
} else {
self.f2()
}
}
}
fn main() {
let mut a = A;
}
Playground
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:16:13
|
13 | if let Some(x) = self.f1() {
| ---- first mutable borrow occurs here
...
16 | self.f2()
| ^^^^ second mutable borrow occurs here
17 | }
| - first borrow ends here
Doesn't the scope of the borrow for self begin and end with the self.f1() call? Once the call from f1() has returned f1() is not using self anymore hence the borrow checker should not have any problem with the second borrow. Note the following code fails too...
// ...
if let Some(x) = self.f1() {
self.f2()
}
// ...
Playground
I think the second borrow should be fine here since f1 and f3 are not using self at the same time as f2.
I put together an example to show off the scoping rules here:
struct Foo {
a: i32,
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo: {}", self.a);
}
}
fn generate_temporary(a: i32) -> Option<Foo> {
if a != 0 { Some(Foo { a: a }) } else { None }
}
fn main() {
{
println!("-- 0");
if let Some(foo) = generate_temporary(0) {
println!("Some Foo {}", foo.a);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(foo) = generate_temporary(1) {
println!("Some Foo {}", foo.a);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(Foo { a: 1 }) = generate_temporary(1) {
println!("Some Foo {}", 1);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(Foo { a: 2 }) = generate_temporary(1) {
println!("Some Foo {}", 1);
} else {
println!("None");
}
println!("-- 1");
}
}
This prints:
-- 0
None
-- 1
-- 0
Some Foo 1
Foo: 1
-- 1
-- 0
Some Foo 1
Foo: 1
-- 1
-- 0
None
Foo: 1
-- 1
In short, it seems that the expression in the if clause lives through both the if block and the else block.
On the one hand it is not surprising since it is indeed required to live longer than the if block, but on the other hand it does indeed prevent useful patterns.
If you prefer a visual explanation:
if let pattern = foo() {
if-block
} else {
else-block
}
desugars into:
{
let x = foo();
match x {
pattern => { if-block }
_ => { else-block }
}
}
while you would prefer that it desugars into:
bool bypass = true;
{
let x = foo();
match x {
pattern => { if-block }
_ => { bypass = false; }
}
}
if not bypass {
else-block
}
You are not the first one being tripped by this, so this may be addressed at some point, despite changing the meaning of some code (guards, in particular).
It's annoying, but you can work around this by introducing an inner scope and changing the control flow a bit:
fn f3(&mut self) {
{
if let Some(x) = self.f1() {
// ...
return;
}
}
self.f2()
}
As pointed out in the comments, this works without the extra braces. This is because an if or if...let expression has an implicit scope, and the borrow lasts for this scope:
fn f3(&mut self) {
if let Some(x) = self.f1() {
// ...
return;
}
self.f2()
}
Here's a log of an IRC chat between Sandeep Datta and mbrubeck:
mbrubeck: std:tr::Chars contains a borrowed reference to the string that created it. The full type name is Chars<'a>. So f1(&mut self) -> Option<Chars> without elision is f1(&'a mut self) -> Option<Chars<'a>> which means that self remains borrowed as long as
the return value from f1 is in scope.
Sandeep Datta: Can I use 'b for self and 'a for Chars to avoid this problem?
mbrubeck: Not if you are actually returning an iterator over something from self. Though if you can make a function from &self -> Chars (instead of &mut self -> Chars) that would fix the issue.
As of Rust 2018, available in Rust 1.31, the original code will work as-is. This is because Rust 2018 enables non-lexical lifetimes.
A mutable reference is a very strong guarantee: that there's only one pointer to a particular memory location. Since you've already had one &mut borrow, you can't also have a second. That would introduce a data race in a multithreaded context, and iterator invalidation and other similar issues in a single-threaded context.
Right now, borrows are based on lexical scope, and so the first borrow lasts until the end of the function, period. Eventually, we hope to relax this restriction, but it will take some work.
Here is how you can get rid of the spurious errors. I am new to Rust so there may be serious errors in the following explanation.
use std::str::Chars;
struct A<'a> {
chars: Chars<'a>,
}
The 'a here is a lifetime parameter (just like template parameters in C++). Types can be parameterised by lifetimes in Rust.
The Chars type also takes a lifetime parameter. What this implies is that the Chars type probably has a member element which needs a lifetime parameter. Lifetime parameters only make sense on references (since lifetime here actually means "lifetime of a borrow").
We know that Chars needs to keep a reference to the string from which it was created, 'a will probably be used to denote the source string's lifetime.
Here we simply supply 'a as the lifetime parameter to Chars telling the Rust compiler that the lifetime of Chars is the same as the lifetime of the struct A. IMO "lifetime 'a of type A" should be read as "lifetime 'a of the references contained in the struct A".
I think the struct implementation can be parameterised independently from the struct itself hence we need to repeat the parameters with the impl keyword. Here we bind the name 'a to the lifetime of the struct A.
impl<'a> A<'a> {
The name 'b is introduced in the context of the function f2. Here it is used to bind with the lifetime of the reference &mut self.
fn f2<'b>(&'b mut self) {}
The name 'b is introduced in the context of the function f1.This 'b does not have a direct relationship with the 'b introduced by f2 above.
Here it is used to bind with the lifetime of the reference &mut self. Needless to say this reference also does not have any relationship with the &mut self in the previous function, this is a new independent borrow of self.
Had we not used explicit lifetime annotation here Rust would have used its lifetime elision rules to arrive at the following function signature...
//fn f1<'a>(&'a mut self) -> Option<Chars<'a>>
As you can see this binds the lifetime of the reference &mut self parameter to the lifetime of the Chars object being returned from this function (this Chars object need not be the same as self.chars) this is absurd since the returned Chars will outlive the &mut self reference. Hence we need to separate the two lifetimes as follows...
fn f1<'b>(&'b mut self) -> Option<Chars<'a>> {
self.chars.next();
Remember &mut self is a borrow of self and anything referred to by &mut self is also a borrow. Hence we cannot return Some(self.chars) here. self.chars is not ours to give (Error: cannot move out of borrowed content.).
We need to create a clone of self.chars so that it can be given out.
Some(self.chars.clone())
Note here the returned Chars has the same lifetime as the struct A.
And now here is f3 unchanged and without compilation errors!
fn f3<'b>(&'b mut self) {
if let Some(x) = self.f1() { //This is ok now
} else {
self.f2() //This is also ok now
}
}
The main function just for completeness...
fn main() {
let mut a = A { chars:"abc".chars() };
a.f3();
for c in a.chars {
print!("{}", c);
}
}
I have updated the code the make the lifetime relationships clearer.

What types are valid for the `self` parameter of a method?

I wanted to create a method that only works where the self parameter was an Rc. I saw that I could use Box, so I thought I might try to mimic how that works:
use std::rc::Rc;
use std::sync::Arc;
struct Bar;
impl Bar {
fn consuming(self) {}
fn reference(&self) {}
fn mutable_reference(&mut self) {}
fn boxed(self: Box<Bar>) {}
fn ref_count(self: Rc<Bar>) {}
fn atomic_ref_count(self: Arc<Bar>) {}
}
fn main() {}
Yields these errors:
error[E0308]: mismatched method receiver
--> a.rs:11:18
|
11 | fn ref_count(self: Rc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::rc::Rc`
|
= note: expected type `Bar`
= note: found type `std::rc::Rc<Bar>`
error[E0308]: mismatched method receiver
--> a.rs:12:25
|
12 | fn atomic_ref_count(self: Arc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::sync::Arc`
|
= note: expected type `Bar`
= note: found type `std::sync::Arc<Bar>`
This is with Rust 1.15.1.
Before Rust 1.33, there are only four valid method receivers:
struct Foo;
impl Foo {
fn by_val(self: Foo) {} // a.k.a. by_val(self)
fn by_ref(self: &Foo) {} // a.k.a. by_ref(&self)
fn by_mut_ref(self: &mut Foo) {} // a.k.a. by_mut_ref(&mut self)
fn by_box(self: Box<Foo>) {} // no short form
}
fn main() {}
Originally, Rust didn't have this explicit self form, only self, &self, &mut self and ~self (the old name for Box). This changed so that only by-value and by-references have the short-hand built-in syntax, since they are the common cases, and have very key language properties, while all smart pointers (including Box) require the explicit form.
As of Rust 1.33, some additional selected types are available for use as self:
Rc
Arc
Pin
This means that the original example now works:
use std::{rc::Rc, sync::Arc};
struct Bar;
impl Bar {
fn consuming(self) { println!("self") }
fn reference(&self) { println!("&self") }
fn mut_reference(&mut self) { println!("&mut self") }
fn boxed(self: Box<Bar>) { println!("Box") }
fn ref_count(self: Rc<Bar>) { println!("Rc") }
fn atomic_ref_count(self: Arc<Bar>) { println!("Arc") }
}
fn main() {
Bar.consuming();
Bar.reference();
Bar.mut_reference();
Box::new(Bar).boxed();
Rc::new(Bar).ref_count();
Arc::new(Bar).atomic_ref_count();
}
However, the impl handling hasn't yet been fully generalised to match the syntax, so user-created types still don't work. Progress on this is being made under the feature flag arbitrary_self_types and discussion is taking place in the tracking issue 44874.
(Something to look forward to!)
It's now possible to use arbitrary types for self, including Arc<Self>, but the feature is considered unstable and thus requires adding this crate attribute:
#![feature(arbitrary_self_types)]
Using feature crate attributes requires using nightly Rust.

Resources