Is it possible to make a bind to object method? For example, I have a vector and a lot of functions which do something if some item exists in the vector. I would implement it as follows:
fn perform_if_exists(item: u8, vector: &Vec<u8>, func: fn(usize)) {
let idx = vector.iter().position(|i| *i == item );
match idx {
Some(i) => func(i),
None => {},
}
}
fn main() {
let v: Vec<u8> = vec![1, 2, 3];
perform_if_exists(1, &v, Vec<_>::remove);
}
but it gives a lot of errors. I think they are reasonable but it's because I don't understand how to put vector's method as argument to a function.
Just as passing objects to functions as arguments is an efficient way of moving information to where it's needed, so is using objects as return values. Functions can either manipulate objects that you pass to them and then return them, or they can return brand-new objects that they create in the function body.
JavaScript Function bind() With the bind() method, an object can borrow a method from another object. The example below creates 2 objects (person and member).
To pass an object as an argument we write the object name as the argument while calling the function the same way we do it for other variables. Syntax: function_name(object_name); Example: In this Example there is a class which has an integer variable 'a' and a function 'add' which takes an object as argument.
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Is it possible
Sure it is. You have to fix the multiple cascading errors first:
Vec<_>::remove
isn't valid.Vec::remove
modifies a Vec
, so you have to pass in a Vec
somehow.Vec::remove
modifies a Vec
, so you have to declare that the function is allowed to do so.Vec::remove
returns the removed value, so you have to allow the function to return a value, even if it's thrown away.fn perform_if_exists<F, R>(item: u8, vector: &mut Vec<u8>, func: F)
where
F: Fn(&mut Vec<u8>, usize) -> R,
{
let idx = vector.iter().position(|i| *i == item);
if let Some(i) = idx {
func(vector, i);
}
}
fn main() {
let mut v = vec![1, 2, 3];
perform_if_exists(1, &mut v, Vec::remove);
println!("{:?}", v);
}
I switched to a generic as that's generally how you will accept closures. A function pointer is fine but more restrictive.
A method in Rust is nothing more than a function, which also takes a first self
parameter. The method Vec::remove
takes two arguments: &mut self
and index: usize
. The self
parameter is always of type Self
, which is Vec<u8>
in this case. The complete type of Vec::<u8>::remove
is: fn(&mut Vec<u8>, usize) -> u8
(yes it also returns the removed element).
After changing the type in your code (+ a few minor mistakes), it works:
// vvv-- has to be mutable
fn perform_if_exists(item: u8, vector: &mut Vec<u8>, func: fn(&mut Vec<u8>, usize) -> u8) {
let idx = vector.iter().position(|i| *i == item );
match idx {
Some(i) => {
func(vector, i);
},
None => {},
}
}
fn main() {
let mut v: Vec<u8> = vec![1, 2, 3];
perform_if_exists(1, &mut v, Vec::remove);
}
But fn(...) -> ...
types are raw pointer types and just work for ordinary functions. Often you also want to enable the user to pass anything that is "callable", like closures. There are traits exactly for that purpose: Fn(...) -> ...
.
Let me propose another solution:
fn perform_if_exists<T, F, R>(item: T, vector: &mut Vec<T>, func: F) -> Option<R>
where F: FnOnce(&mut Vec<T>, usize) -> R,
T: PartialEq
{
let idx = vector.iter().position(|i| *i == item );
idx.map(|i| func(vector, i))
}
This solution is far more generic as it allows arbitrary item types, arbitrary "callable" types and returns the value that is returned by the given function. Note that the main
function didn't change; the solution is more generic, but all old uses still work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With