Understanding Rust Borrowing/Stack Complications - rust

This rust code doesn't work. Is there any detailed explanation for why?
It gives the error "cannot return reference to temporary value"
trait NonInherited {
fn get_type(&self) -> &str;
}
struct Inherited {
val: usize,
}
impl NonInherited for Inherited {
fn get_type(&self) -> &str {
return "inherited";
}
}
fn helper(list: &mut [usize; 2]) -> &'static dyn NonInherited {
// works
//return &Inherited {val: 3};
// does not work
return &Inherited {val: list[1]}; // Error is here
}
fn main() {
let mut a: [usize; 2] = [1, 7];
println!("{}", helper(&mut a).get_type());
}

My understanding is that Inherited { val: 3 } is a constant struct expression that is evaluated during compilation, however, Inherited { val: list[1] } is dynamic which is evaluated during runtime.
As described in Rust reference on Constant Evaluation, constant expressions do not cause any drop() to be run, thus, its value is not temporary.

The problem here is that the Inherited struct is created on the stack in the function helper, and then a reference to this stack-resident object is being returned. That's a problem because the lifetime of the Inherited struct is only for the scope of the helper function.
You can fix this by returning the created struct itself instead of a reference to it. Below is a simple working example, with some of the type names changed for clarity. Notice that the list variable does not need to be mut.
trait SomeTrait {
fn get_type(&self) -> &str;
}
struct SomeStruct {
val: usize,
}
impl SomeTrait for SomeStruct {
fn get_type(&self) -> &str {
return "overridden";
}
}
fn helper(list: &[usize; 2]) -> impl SomeTrait {
// works
return SomeStruct {val: list[1]};
}
fn main() {
let a: [usize; 2] = [1, 7];
let b = helper(&a);
println!("Type is {}", b.get_type());
}

Related

How can we return a static reference to a variable we make in a function in rust?

struct Foo<'a>(&'a str);
impl<'a> Foo<'a> {
fn get(&self) -> &'static str {self.0}
}
fn main() {
let value: &str;
{
let foo = Foo("Test Value");
value = foo.get();
}
println!("{}", value);
}
In this test code, I need to get the value stored in foo but as str is not sized, I can't just copy it's value. I even tried cloning the str. In a real life scenario, I could just use String or make a wrapper or encapsulate it in a box and return it but is there no way I can return a static reference to a variable I create in a function? If so, how does the as_str function work in rust?
----Edit----
In this example, Neither putting 'static before str in Foo nor returning value with lifetime 'a works. What to do then?
struct Foo<'a>(&'a [i32]);
impl<'a> Foo<'a> {
fn get(&self) -> &'static [i32] {self.0}
}
fn main() {
let value: &[i32];
{
let test_value = [0, 1, 2, 3];
let foo = Foo(&test_value);
value = foo.get();
}
println!("{:?}", value);
}
You can do it like this:
struct Foo<'a>(&'a str);
impl<'a> Foo<'a> {
fn get(&self) -> &'a str {self.0}
}
fn main() {
let value: &str;
{
let foo = Foo("Test Value");
value = foo.get();
}
println!("{}", value);
}
Or like this:
struct Foo(&'static str);
impl Foo {
fn get(&self) -> &'static str {self.0}
}
fn main() {
let value: &str;
{
let foo = Foo("Test Value");
value = foo.get();
}
println!("{}", value);
}
The reason your code doesn't compile is that you're declaring you are returning a reference with a (potentially) longer lifetime. Compare the lifetime of static with that of a (self.0 has a lifetime of a).

Is there a way to create a struct based on a trait implementation?

I'm trying to use a struct with multiple implementations of one method:
trait Trait { fn apply(&self) -> vec<usize>; }
struct Bar<X> { vec: Vec<usize> }
impl<X> Bar<X> {
pub fn new(vec: Vec<usize>) -> Self { Self{vec} }
pub fn test(&self) {
// Things here
println!("Method: {:?}", self.apply());
// Things there
}
}
impl Trait for Bar<ThisWay> {
fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x.pow(2)).collect() }
}
impl Trait for Bar<ThatWay> {
fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x + 2).collect() }
}
fn main() {
Bar<ThisWay>::new(vec![1,2,3]).test();
Bar<ThatWay>::new(vec![1,2,3]).test();
}
Which would return:
>>> [1,4,9];
>>> [3,4,5];
I know I could create 2 structs implementing these methods differently, but that feels wrong as it's potentially a lot of redundant code.
I also know I could have a reference to that implementation method:
trait Trait { fn apply(vec: &Vec<usize>) -> Vec<usize>; }
impl Struct{
// fn new
test(&self, t: &impl Trait) {
// Things here
println!("{:?}", t::apply(&self.vec));
// Things there
}
}
struct ThisWay;
struct ThatWay;
impl Trait for ThisWay {fn apply(vec: &Vec<usize>) -> Vec<usize> {///} };
impl Trait for ThatWay {fn apply(vec: &Vec<usize>) -> Vec<usize> {///} };
fn main() {
let this_way = ThisWay{};
let that_way = ThatWay{};
let problem = Bar::new(vec![1,2,3]);
problem.test(&this_way);
problem.test(&that_way);
}
This approach seems needlessly complicated when I would want to use many arguments inside given struct:
fn hill_climber(&self, nullary_op: &impl NullaryOperator, unary_op: &impl UnaryOperator, ...) {
self.vec = nullary_op();
self.vec = unary_op(&self.vec, self.n, self.m, self.jobs, self.stuff, ...);
}
This seems to be a cursed way of writing code. What happens when a method implementation doesn't use a parameter e.g m, and other uses that?
Traits are used to define shared behaviour. In your example, you want to implement the same trait in different ways. This goes against the purpose of a trait. Instead of having two structs as you tried, you should probably have two traits:
trait ThisWay {
fn apply(&self) -> Vec<usize>;
}
trait ThatWay {
fn apply(&self) -> Vec<usize>;
}
Now you can implement both traits for your struct:
struct Bar {
vec: Vec<usize>,
}
impl ThisWay for Bar {
fn apply(&self) -> Vec<usize> {
self.vec.iter().map(|x| x.pow(2)).collect()
}
}
impl ThatWay for Bar {
fn apply(&self) -> Vec<usize> {
self.vec.iter().map(|x| x + 2).collect()
}
}
Because Bar implements ThisWay and ThatWay, it now has two definitions for the apply method. To disambiguate between them, we have to use Fully Qualified Syntax:
let this_bar = Bar::new(vec![1, 2, 3]);
println!("Method: {:?}", <Bar as ThisWay>::apply(&this_bar));
let that_bar = Bar::new(vec![1, 2, 3]);
println!("Method: {:?}", <Bar as ThatWay>::apply(&that_bar));
And, as expected, you get two different outputs:
Method: [1, 4, 9]
Method: [3, 4, 5]
As an alternative to the other answer, you can also use something more similar to your original example, using generics and zero-sized struct types as "markers" for which method you want to use. Here's a complete example:
// PhantomData allows us to "use" a generic without having an actual field
use std::marker::PhantomData;
// These structs will be used to indicate which implementation we want
struct ThisWay;
struct ThatWay;
trait Trait { fn apply(&self) -> Vec<usize>; }
struct Bar<X> {
vec: Vec<usize>,
// This extra field is here to stop the compiler complaining about not using X
_marker: PhantomData<X>,
}
impl<X> Bar<X> {
pub fn new(vec: Vec<usize>) -> Self { Self { vec, _marker: PhantomData } }
// Note the new "where" clause here - we can only implement this function if Bar<X> implements Trait
pub fn test(&self) where Self: Trait {
// Things here
println!("Method: {:?}", self.apply());
// Things there
}
}
impl Trait for Bar<ThisWay> {
fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x.pow(2)).collect() }
}
impl Trait for Bar<ThatWay> {
fn apply(&self) -> Vec<usize> { self.vec.iter().map(|x| x + 2).collect() }
}
fn main() {
Bar::<ThisWay>::new(vec![1,2,3]).test();
Bar::<ThatWay>::new(vec![1,2,3]).test();
}
Running this, the output correctly reflects the different functions being used:
Method: [1, 4, 9]
Method: [3, 4, 5]
This approach has different semantics from the other answer: whereas the other answer allows you to construct a Bar that's capable of being used with both functions, this approach locks you into one implementation at the type level, since Bar<ThisWay> and Bar<ThatWay> are two separate types that each only provide only one apply function. This can be desirable for type safety in some scenarios, but may not be what you need for this particular case.
// since x is declared as `Bar<ThatWay>`, we can only ever use the `ThatWay` implementation of `apply`/`test`
let x: Bar<ThatWay> = Bar::new(vec![1, 2, 3]);
x.test(); // -> Method: [3, 4, 5]

Storing types in a HashMap to dynamically instantiate them

I am trying to store structs in a HashMap keyed by string so that I can later create new objects by string. Think of a REST API where clients can get the server to instantiate a specific object by supplying a name.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", MyStruct);
h.insert("MyOtherStruct", MyOtherStruct);
// This is pseudo-code
let obj = h.get("MyStruct").unwrap()::new();
}
As I expected, this doesn't work due to syntax errors:
error: expected one of `.`, `;`, `?`, or an operator, found `::`
--> src/main.rs:25:41
|
25 | let obj = h.get("MyStruct").unwrap()::new();
| ^^ expected one of `.`, `;`, `?`, or an operator here
My second attempt was to store a reference to the new method of each struct instead of the types themselves.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", &MyStruct::new);
h.insert("MyOtherStruct", &MyOtherStruct::new);
let obj = h.get("MyStruct").unwrap()();
}
This fails because the fn items have different types and can't be stored in the same HashMap:
error[E0308]: mismatched types
--> src/main.rs:22:31
|
22 | h.insert("MyOtherStruct", &MyOtherStruct::new);
| ^^^^^^^^^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected type `&fn() -> MyStruct {MyStruct::new}`
found type `&fn() -> MyOtherStruct {MyOtherStruct::new}`
Since I'm pretty new to Rust, I'm out of ideas. How can I solve this problem?
This is ultimately fundamentally impossible. In Rust, local variables are stored on the stack, which means that they have to have a fixed size, known at compile time. Your construction requires the size of the value on the stack to be determined at runtime.
The closest alternative is to move to trait objects, which introduce a layer of indirection:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {}
struct MyStruct;
impl NewThing for MyStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyStruct {}
struct MyOtherStruct;
impl NewThing for MyOtherStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyOtherStruct {}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStruct));
h.insert("MyOtherStruct", Box::new(MyOtherStruct));
let obj = h["MyStruct"].new();
}
You will find this pattern out in the world, such as in hyper's NewService.
what is [the value of &self of method new] when calling h["MyStruct"].new()
It's an instance of MyStruct or MyOtherStruct. The only reason that the same type can implement both traits is because there's no real unique state for the "factory" and the "instance". In more complicated implementations, these would be two different types.
Using the same type is common for such cases as sharing a reference-counted value.
See also:
Is it possible to have a constructor function in a trait?
Here is a more complex example of #Shepmaster's solution, using different types for Factories and the objects themselves:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {
fn execute(&mut self);
}
// MyStruct
struct MyStructFactory;
impl NewThing for MyStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyStruct {test: 12, name: "Test".into()})
}
}
struct MyStruct {
test: i32,
name: String
}
impl Thing for MyStruct {
fn execute(&mut self) {
self.test+=1;
println!("MyStruct {} {}", self.test, self.name);
}
}
// MyOtherStruct
struct MyOtherStructFactory;
impl NewThing for MyOtherStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyOtherStruct {my_member: 1})
}
}
struct MyOtherStruct {
my_member: u32
}
impl Thing for MyOtherStruct {
fn execute(&mut self) { println!("MyOtherStruct.my_member: {}", self.my_member); }
}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStructFactory));
h.insert("MyOtherStruct", Box::new(MyOtherStructFactory));
h["MyStruct"].new().execute();
h["MyOtherStruct"].new().execute();
}
You could use std::any::Any to erase the type of the entry. They use Any::downcast<T> to check if the entry at the location matches your type, and get a Ok(Box<T>)

error: `line` does not live long enough (but I know it does)

I am trying to make some kind of ffi to a library written in C, but got stuck. Here is a test case:
extern crate libc;
use libc::{c_void, size_t};
// this is C library api call
unsafe fn some_external_proc(_handler: *mut c_void, value: *const c_void,
value_len: size_t) {
println!("received: {:?}" , std::slice::from_raw_buf(
&(value as *const u8), value_len as usize));
}
// this is Rust wrapper for C library api
pub trait MemoryArea {
fn get_memory_area(&self) -> (*const u8, usize);
}
impl MemoryArea for u64 {
fn get_memory_area(&self) -> (*const u8, usize) {
(unsafe { std::mem::transmute(self) }, std::mem::size_of_val(self))
}
}
impl <'a> MemoryArea for &'a str {
fn get_memory_area(&self) -> (*const u8, usize) {
let bytes = self.as_bytes();
(bytes.as_ptr(), bytes.len())
}
}
#[allow(missing_copy_implementations)]
pub struct Handler<T> {
obj: *mut c_void,
}
impl <T> Handler<T> {
pub fn new() -> Handler<T> { Handler{obj: std::ptr::null_mut(),} }
pub fn invoke_external_proc(&mut self, value: T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
// this is Rust wrapper user code
fn main() {
let mut handler_u64 = Handler::new();
let mut handler_str = Handler::new();
handler_u64.invoke_external_proc(1u64); // OK
handler_str.invoke_external_proc("Hello"); // also OK
loop {
match std::io::stdin().read_line() {
Ok(line) => {
let key =
line.trim_right_matches(|&: c: char| c.is_whitespace());
//// error: `line` does not live long enough
// handler_str.invoke_external_proc(key)
}
Err(std::io::IoError { kind: std::io::EndOfFile, .. }) => break ,
Err(error) => panic!("io error: {}" , error),
}
}
}
Rust playpen
I get "line does not live long enough" error if I uncomment line inside the loop. In fact, I realize that Rust is afraid that I could store short-living reference to a slice somewhere inside Handler object, but I quite sure that I wouldn't, and I also know, that it is safe to pass pointers to the external proc (actually, memory is immidiately copied at the C library side).
Is there any way for me to bypass this check?
The problem is that you are incorrectly parameterizing your struct, when you really want to do it for the function. When you create your current Handler, the struct will be specialized with a type that includes a lifetime. However, the lifetime of line is only for the block, so there can be no lifetime for Handler that lasts multiple loop iterations.
What you want is for the lifetime to be tied to the function call, not the life of the struct. As you noted, if you put the lifetime on the struct, then the struct is able to store references of that length. You don't need that, so put the generic type on the function instead:
impl Handler {
pub fn new() -> Handler { Handler{obj: std::ptr::null_mut(),} }
pub fn invoke_external_proc<T>(&mut self, value: T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
Amended answer
Since you want to specialize the struct on a type, but don't care too much about the lifetime of the type, let's try this:
#[allow(missing_copy_implementations)]
pub struct Handler<T: ?Sized> {
obj: *mut c_void,
}
impl<T: ?Sized> Handler<T> {
pub fn new() -> Handler<T> { Handler{ obj: std::ptr::null_mut() } }
pub fn invoke_external_proc(&mut self, value: &T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
Here, we allow the type to be unsized. Since you can't pass an unsized value as a parameter, we now have to take a reference instead. We also have to change the impl:
impl MemoryArea for str {
fn get_memory_area(&self) -> (*const u8, usize) {
let bytes = self.as_bytes();
(bytes.as_ptr(), bytes.len())
}
}

Trying implement builder function with slice in rust

I'm trying implement builder function:
extern crate debug;
use std::mem::size_of_val;
#[deriving(Show, PartialEq)]
pub struct A<'a> {
pub a: &'a [i64],
pub b: &'a str,
}
fn build<'a>() -> A<'a> {
return A { a: &[1,2,3], b: "test" };
}
fn main() {
let a = build();
println!("{} - {} - `{:?}`", a, size_of_val(&a), a);
}
But this give me next compile error:
/prsrc/main.rs:16:20: 16:27 error: borrowed value does not live long enough
/prsrc/main.rs:16 return A { a: &[1,2,3], b: "test" };
^~~~~~~
/prsrc/main.rs:15:25: 17:2 note: reference must be valid for the lifetime 'a as defined on the block at 15:24...
/prsrc/main.rs:15 fn build<'a>() -> A<'a> {
/prsrc/main.rs:16 return A { a: &[1,2,3], b: "test" };
/prsrc/main.rs:17 }
/prsrc/main.rs:16:5: 16:41 note: ...but borrowed value is only valid for the statement at 16:4; consider using a `let` binding to increase its lifetime
/prsrc/main.rs:16 return A { a: &[1,2,3], b: "test" };
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
I even try A { a: [1,2,3], b: "test" }, A { a: &'a [1,2,3], b: "test" } and std:rc:Rc::new(A { a: &[1,2,3], b: "test" }) but it still not work.
When I replace &[i64] to Vec<i64>:
fn build<'a>() -> A<'a> {
return A { a: vec![1,2,3], b: "test" };
}
all work right:
A { a: [1, 2, 3], b: test } - 40 - `A<'static>{a: collections::vec::Vec<i64>{len: 3u, cap: 4u, ptr: (0x7f1097426000 as *mut ())}, b: "test"}`
I little confused because as I understand &[i64] implementation should be similar to &str and str work when I replace &[i64] to Vec<i64>.
So how can I implement builder function for slice?
The hint that something is wrong with your lifetimes is here :
fn build<'a>() -> A<'a> { /* ... */ }
You have an output lifetime, but no input lifetime.
The only way this is possible is if your lifetime is in fact 'static, as otherwise it must be linked to at least one of the arguments, which defines it.
So your function should in fact be of type :
fn build() -> A<'static>
But here comes the problem : your two references must thus link to static storage. You are lucky, &str is a special case here. String literals ("test" in your case) are always in static storage. So far so good.
But &[1,2,3] is not in static storage. In fact, this shortcut is equivalent to :
let temp = [1,2,3];
return A { a: &temp, b: "test" };
and now, the lifetime issue becomes obvious.
The fix is quite simple : make the temporary variable explicitly 'static, like this :
fn build() -> A<'static> { //'
static temp: [i64, ..3] = [1,2,3];
return A { a: &temp, b: "test" };
}

Resources