I have a struct, which sometimes I instantiate statically, and sometimes I'd like users to allocate on the heap. Is it possible to allow both in as arguments to a function?
pub struct MyData {
x: i32
}
static ALLOCATED_STATICALLY: MyData = MyData {x: 1};
// what should my signature be?
fn use_data(instance: Box<MyData>) {
println!("{}", instance.x);
}
fn main () {
use_data(Box::new(MyData{x: 2}));
// this doesn't work currently
use_data(ALLOCATED_STATICALLY);
}
In both instances, you can pass a pointer to the function.
pub struct MyData {
x: i32
}
static ALLOCATED_STATICALLY: MyData = MyData { x: 1 };
// what should my signature be?
fn use_data(instance: &MyData) {
println!("{}", instance.x);
}
fn main () {
use_data(&Box::new(MyData{ x: 2 }));
use_data(&ALLOCATED_STATICALLY);
}
Note that in both cases, the caller needs to use the & operator to take the address of the value. In the first call, the operator yields a &Box<MyData>, but the compiler automatically converts it to a &MyData because Box implements the Deref trait.
Related
In my model, I have a Petgraph graph which stores as nodes a struct with fields as followed:
struct ControlBloc
{
name:String,
message_inbox:Vec<MessageObj>,
blocked:bool,
instruct:String,
inbox_capacity:f64,
buffer:Vec<MessageObj>,
number_discarded:u32,
clock_queue:SendingQueue,
clock_speed:f64,
}
In it there is a field called instruct in which I want to store instructions. I want to code the model in a way such that after some time, all the nodes will execute the instructions that are stored in the struct. Instructions can be for example send messages to other nodes, computing something... I want something versatile.
Is there a way to store functions as fields in a struct? and then after some time, the function stored can be called and whatever function will be executed?
One way that I see doing this is maybe using enum to store all the function names then using a function to map whatever enum to the corresponding function, for example:
enum FuncName {
SendMessage,
ComputeSize,
StoreSomething,
DoNothing,
}
fn exec_function(func:FuncName)
{
match func {
FuncName::SendMessage => send_message_function(input1,input2),
FuncName::ComputeSize => compute_size_function(input1,input2,input3),
FuncName::StoreSomething => store_something_funtion(input1),
FuncName::DoNothing => (),
}
}
However in this case you can't really customize the inputs of the FuncName function and they either have to be always preset to the same thing or in the input of exec_function you add all the different inputs fields of all the functions in FuncName but that seems rather overkill, even then, I dont really see how to pass them and store in the struct.
Is there then a way to directly add the functions or something in the struct? I know I'm breaking many Rust rules but say for example I had a variable already declared let bloc = ControlBloc::new(...); then you could set the function as for example bloc.instruct = send_message_function(node1,node2); and then when you called bloc.instruct then that would call whatever function is stored there.
Is something like this possible or am I dreaming or like very difficult (I am still learning the language)?
What you can do is storing Box<dyn Fn()> in your struct:
struct Foo {
instruct: Box<dyn Fn(Vec<i32>)>
}
fn sum(vec: Vec<i32>) {
let sum: i32 = vec.into_iter().sum();
println!("{}", sum);
}
fn main() {
let foo = Foo {
instruct: Box::new(|vec| {
let sum: i32 = vec.into_iter().sum();
println!("{}", sum);
})
};
(foo.instruct)(vec![1, 2, 3, 4]);
let foo = Foo {
instruct: Box::new(sum)
};
(foo.instruct)(vec![1, 2, 3, 4]);
}
Fn is implemented automatically by closures which only take immutable references to captured variables or don’t capture anything at all, as well as (safe) function pointers (with some caveats, see their documentation for more details). Additionally, for any type F that implements Fn, &F implements Fn, too.
#EDIT
In my example I used Vec<i32> as an abstract for multiple arguments. However if you are going to have some set of instructions that have different count of arguments, but within itself always the same, you might consider creating a trait Instruct and create struct for every different instruct that will implement this.
Playground
struct Foo<T> {
instruct: Box<dyn Instruct<T>>
}
trait Instruct<T> {
fn run(&self) -> T;
}
struct CalcSum {
f: Box<dyn Fn() -> i32>
}
impl CalcSum {
fn new(arg: Vec<i32>) -> CalcSum {
CalcSum {
f: Box::new(move || arg.iter().sum::<i32>()),
}
}
}
impl Instruct<i32> for CalcSum {
fn run(&self) -> i32 {
(self.f)()
}
}
In C++, we can overload operator bool() to convert a struct to bool:
struct Example {
explicit operator bool() const {
return false;
}
};
int main() {
Example a;
if (a) { /* some work */ }
}
Can we do something simple (and elegant) in Rust so to:
pub struct Example {}
fn main() {
let k = Example {};
if k {
// some work
}
}
There's no direct equivalent of operator bool(). A close alternative would be to implement From (which will also implement Into) and call the conversion explicitly:
pub struct Example;
impl From<Example> for bool {
fn from(_other: Example) -> bool {
false
}
}
fn main() {
let k = Example;
if k.into() {
// some work
}
}
This will take ownership of Example, meaning you can't use k after it's been converted. You could implement it for a reference (impl From<&Example> for bool) but then the call site becomes uglier ((&k).into()).
I'd probably avoid using From / Into for this case. Instead, I'd create a predicate method on the type. This will be more readable and can take &self, allowing you to continue using the value.
See also:
When should I implement std::convert::From vs std::convert::Into?
Rust does not have C++'s implicit type conversion via operator overloading. The closest means of implicit conversion is through a Deref impl, which provides a reference of a different type.
What is possible, albeit not necessarily idiomatic, is to implement the not operator ! so that it returns a boolean value, and perform the not operation twice when needed.
use std::ops::Not;
pub struct Example;
impl Not for Example {
type Output = bool;
fn not(self) -> bool { false }
}
fn main() {
let k = Example;
if !!k {
println!("OK!");
} else {
println!("WAT");
}
}
Playground
You have a few options, but I'd go for one of these:
Into<bool> (From<Example>)
If your trait conceptually represents a bool, but maybe with some extra metadata, you can implement From<Example> for bool:
impl From<Example> for bool {
fn from(e: Example) {
// perform the conversion
}
}
Then you can:
fn main() {
let x = Example { /* ... */ };
if x.into() {
// ...
}
}
Custom method
If your type doesn't really represent a boolean value, I'd usually go for an explicit method:
impl Example {
fn has_property() -> bool { /* ... */ }
}
This makes it more obvious what the intent is, for example, if you implemented From<User> for bool:
fn main() {
let user = User { /* ... */ };
if user.into() {
// when does this code get run??
}
// compared to
if user.logged_in() {
// much clearer
}
}
You can implement std::ops::Deref with the bool type. If you do that, you have to call *k to get the boolean.
This is not recommended though, according to the Rust documentation:
On the other hand, the rules regarding Deref and DerefMut were designed specifically to accommodate smart pointers. Because of this, Deref should only be implemented for smart pointers to avoid confusion.
struct Example {}
impl std::ops::Deref for Example {
type Target = bool;
fn deref(&self) -> &Self::Target {
&true
}
}
fn main() {
let k = Example {};
if *k {
// some work
}
}
Playground
I have a function that will create one of several structs (all of which have a method of the same signature but have other, different, methods and traits); I would like to instance one of the structs in a function and return a reference to its method that can be called elsewhere.
// Pseudocode
type SizeGetter = fn()-> isize;
fn get_ref()-> &SizeGetter{
let catch = Fish{weight: 12};
&catch.get_weight()
//Fish.get_weight() is used here but it may be any struct.method() -> isize
}
fn main() {
let getit = get_ref();
println!("{}", getit());
}
In the above my goal is to define catch.getweight() in a function, return a reference to that function and then call it later to get the size.
That original attempt could not work because you cannot return a reference to something created in a function. In this case, returning something equivalent to a method to a locally created struct value requires the value to outlive the function's lifetime as well.
We can reference a method bar in a struct Foo with Foo::bar, but this one isn't bound to a receiver value. There is no syntax specifically for referencing a method call on a value. The solution instead is to create a closure that captures the value and calls the method.
let foo = Foo::new();
move || foo.bar()
Considering this Fish struct and implementation (adjusted to comply with naming conventions):
struct Fish {
weight: usize,
}
impl Fish {
fn weight(&self) -> usize {
self.weight
}
}
A function returning another self-sufficient function would be written like so:
fn fish_weight() -> impl Fn() -> usize {
let r#catch = Fish { weight: 12 };
move || r#catch.weight()
}
Using:
let get = fish_weight();
println!("Fish weight: {}", get());
Playground
I want to pass a member function of a struct to another struct.
Sorry, poor English, can't say more details.
use std::thread;
struct Struct1 {}
impl Struct1 {
pub fn do_some(&mut self, s: &str) {
// do something use s to modify self
}
}
struct Struct2 {
cb1: Box<Fn(&mut Struct1, &str)>,
}
fn main() {
let s1 = Struct1 {};
let s2 = Struct2 {
cb1: Box::new(s1.do_some), // how to store do_some function in cb1 ?
};
}
You were very close! To refer to a method or any other symbol you use the :: separator and specify the path to said symbol. Methods or associated functions live in the namespace of the type, therefore the path of your method is Struct1::do_some. In Java you would also use the . operator to access those, but in Rust the . operator is only used on existing objects, not on type names.
The solution thus is:
let s2 = Struct2 {
cb1: Box::new(Struct1::do_some),
};
However, you could possibly improve the type of your function a bit. Box<Fn(...)> is a boxed trait object, but you don't necessarily need that if you don't want to work with closures. If you just want to refer to "normal functions" (those who don't have an environment), you can use a function pointer instead:
struct Struct2 {
cb1: fn(&mut Struct1, &str),
}
Note the lowercase fn and that we don't need the Box.
I'm trying to select a function to call depending on a condition. I want to store that function in a variable so that I can call it again later without carrying the condition around. Here's a working minimal example:
fn foo() {
println! ("Foo");
}
fn bar() {
println! ("Bar");
}
fn main() {
let selector = 0;
let foo: &Fn() = &foo;
let bar: &Fn() = &bar;
let test = match selector {
0 => foo,
_ => bar
};
test();
}
My question is: is it possible to get rid of the intermediate variables? I've tried simply removing them:
fn foo() {
println! ("Foo");
}
fn bar() {
println! ("Bar");
}
fn main() {
let selector = 0;
let test = match selector {
0 => &foo as &Fn(),
_ => &bar as &Fn()
};
test();
}
but then the borrow checker complains that the borrowed values are only valid until the end of the match (btw, why? the functions are 'static anyway so should be valid to the end of times). I've also tried making the 'static lifetime explicit by using &foo as &'static Fn() but that doesn't work either.
The following works, if you only need to work with static functions and not closures:
fn foo() {
println!("Foo");
}
fn bar() {
println!("Bar");
}
fn main() {
let selector = 0;
let test: fn() = match selector {
0 => foo,
_ => bar
};
test();
}
(try on playground)
Here I've used function type instead of function trait.
The reason that the borrowed trait object doesn't work is probably the following. Any trait object is a fat pointer which consists of a pointer to some value and a pointer to a virtual table. When the trait object is created out of a closure, everything is clear - the value would be represented by the closure itself (internally being an instance of a structure containing all captured variables) and the virtual table would contain a pointer to the implementation of the corresponding Fn*() trait generated by the compiler whose body would be the closure body.
With functions, however, things are not so clear. There are no value to create a trait object from because the function itself should correspond to the implementation of Fn() trait. Therefore, rustc probably generates an empty structure and implements Fn() for it, and this implementation calls the static function directly (not actual Rust, but something close):
struct SomeGeneratedStructFoo;
impl Fn<()> for SomeGeneratedStructFoo {
type Output = ();
fn call(&self, args: ()) -> () {
foo();
}
}
Therefore, when a trait object is created out of fn foo(), a reference is taken in fact to a temporary value of type SomeGeneratedStructFoo. However, this value is created inside the match, and only a reference to it is returned from the match, thus this value does not live long enough, and that's what the error is about.
fn() is a function pointer type. It's already a pointer type. You can check this with std::mem::size_of::<fn()>(). It is not a zero-sized type.
When you do &foo, you take a pointer to a stack allocated pointer. This inner pointer does not survive very long, causing the error.
You can cast these to the generic fn() type as suggested. I would be interested in knowing why you can't cast fn() to &Fn(), though.