What is the point of & in Rust if I can omit it? - rust

This is the code:
struct Foo { x: i32 }
fn bar(foo: &Foo) -> i32 {
foo.x
}
It compiles. Then, I remove the & and it also compiles:
fn bar(foo: Foo) -> i32 {
foo.x
}
The question: what's the difference and why it might be necessary to use this symbol here? Let me rephrase: why dereferencing is not syntactically explicit?

foo: &Foo is a reference to a Foo, while foo: Foo is a Foo value.
The first signature declares that the function only borrows foo by taking a reference, the second signature declares that it takes ownership of the value.
Although both compile, and both are correct, there is a difference in how you call them and what you can do in the function body.
First variant:
bar(&foo)
// foo is still available here
Second variant:
bar(foo)
// foo is no longer available here; it was moved into bar
// (unless foo is Copy, in which case it is copied into bar)
Furthermore, if the function bar owns the value foo, it is possible to move fields out of foo. This is not possible if foo is a reference.
Here is a demonstration with a field type that is not Copy:
struct Foo {
x: String,
}
fn bar1(foo: &Foo) -> &String {
// let y = foo.x; // moving out of a reference would not compile
&foo.x // can return a reference to field
}
fn bar2(foo: Foo) -> String {
foo.x // can move x out of foo
}
fn main() {
let foo = Foo {
x: "foo".to_string(),
};
let x: &String = bar1(&foo);
let x: String = bar2(foo);
// bar1(&foo); // would not compile; foo has been moved into bar2 above
}
Playground

Related

Why am I able to write a function type in the type parameter of a struct?

If I understand correctly, in Rust every closure type has a unique type that cannot be written out. I also thought this applied to functions, however, I'm able to do the following, in which I explicitly write the type parameter in the return types of get_struct_1 and get_struct_2:
struct FooStruct<F>
where F: Fn(i32) -> i32
{
f: F,
}
fn foo(x: i32) -> i32 {
2*x
}
fn bar(x: i32) -> i32 {
-1*x
}
fn get_struct_1() -> FooStruct<fn(i32) -> i32>
{
FooStruct { f: foo }
}
fn get_struct_2() -> FooStruct<fn(i32) -> i32>
{
FooStruct { f: bar }
}
// This does not work - the trait has to be boxed
//fn get_struct_3() -> FooStruct<Fn(i32) -> i32>
//{
// FooStruct { f: |x| 10*x }
//}
fn main() {
let mut x = get_struct_1();
// Why does this work - do bar and foo have the same type?
x = get_struct_2();
// Why does this work - doesn't a closure have its own unique, unwriteable type?
x = FooStruct { f: |x| 10*x };
let mut y = FooStruct { f: |x| 10*x };
// Does not work - no two closures have the same type.
//y = FooStruct { f: |x| 10*x };
// Does not work - even though the 'other way around' worked with x.
// But _does_ work if I type-annotate y with FooStruct<fn(i32) -> i32>
//y = get_struct_1();
}
I thought Rust was monomorphic in the way it handles type parameters. So if I do this
struct FooStruct {
f: Box<dyn Fn(i32) -> i32>
}
the program will dynamically determine which f to run at runtime, but the FooStruct<F> version avoids the dynamic dispatch.
This example seems to disagree with that. If the x = get_struct_2(); line were inside an if statement, the compiler would not be able to determine whether x was holding a wrapped version of the function foo or bar.
Closures (and functions for that matter) do have unique, unwriteable types. However, they can also be cast (and implicitly* too) to function pointers when they don't capture any variables, which yours don't. It's essentially the reason why this works:
fn main() {
// closure is inferred to be a function pointer
let mut f: fn() -> i32 = || 5;
// assigning a different function pointer
f = || 6;
}
But this doesn't:
fn main() {
// closure is inferred to be a unique closure type
let mut f = || 5;
// uh oh! different closure type, errors
f = || 6;
}
* it's not so much an implicit cast as implicit type inference

Extracting a function which creates an instance in Rust

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
}

Rust function returns object containing reference of parameter compiles fine, but fails to compile when &self included in parameter list

This code compiles fine.
Foo contains a reference to an object of type X. It has a simple function new() which does this. Then there's a function called foo2() (it can also be a free function outside the impl block) which accepts a reference to X and returns a completely new object of type Foo. This works fine.
The problem is if I uncomment foo() which includes the parameter &self. Suddenly it doesn't work now. Why? If I add lifetimes then it works, but why can it not figure this out? Thanks.
struct X {
}
struct Foo<'a> {
x: &'a X
}
impl<'a> Foo<'a> {
fn new(x: &'a X) -> Self {
Self {
x
}
}
}
struct B {
}
impl B {
// This doesn't work
/*fn foo(&self, x: &X) -> Foo {
Foo::new(x)
}*/
// This does work
fn foo2(x: &X) -> Foo {
Foo::new(x)
}
}
fn main() {
let x = X {};
let b = B {};
//let f = b.foo(&x);
}
But when I uncomment foo() then I get this error:
error[E0623]: lifetime mismatch
--> main.rs:21:9
|
20 | fn foo<'a>(&self, x: &'a X) -> Foo {
| ----- ---
| |
| this parameter and the return type are declared with different
lifetimes...
21 | Foo::new(x)
| ^^^^^^^^^^^ ...but data from `x` is returned here
Is there some kind of ellison happening here which &self messes up? What's going on here? Thanks
This works:
fn foo<'a>(&self, x: &'a X) -> Foo<'a> {
Foo::new(x)
}
But why doesn't the compiler figure this out?
The Rust Reference -> Lifetime elision
If the receiver has type &Self or &mut Self, then the lifetime of that reference to Self is assigned to all elided output lifetime parameters.
There is a reason why compiler try to pickup lifeteime from &self and not from x: &X.

Rust method that accepts and treats any kind of string as immutable and produces a new immutable string?

I'm new to Rust. I want to write a method (trait implementation?) that takes any of a String or a string slice, treats it as immutable, and returns a new immutable string. Let's say foo is a method that doubled whatever input you give it:
let x = "abc".foo(); // => "abcabc"
let y = x.foo(); // => "abcabcabcabc"
let z = "def".to_string().foo(); // => "defdef"
In this case, I do not care about safety or performance, I just want my code to compile for a throwaway test. If the heap grows infinitely, so be it. If this requires two trait implementations, that's fine.
Let's say foo is a method that doubled whatever input you give it.
A trait is a perfectly good way to do this, since it makes one common behavior:
trait Foo {
fn foo(&self) -> String;
}
... applied to multiple types:
impl Foo for String {
fn foo(&self) -> String {
let mut out = self.clone();
out += self;
out
}
}
impl<'a> Foo for &'a str {
fn foo(&self) -> String {
let mut out = self.to_string();
out += self;
out
}
}
Using:
let x = "abc".foo();
assert_eq!(&x, "abcabc");
let z = "shep".to_string().foo();
assert_eq!(&z, "shepshep");
Playground
The output is an owned string. Whether this value immutable or not, as typical in Rust, only comes at play at the calling site.
See also:
What's the difference between placing "mut" before a variable name and after the ":"?
If you want a borrowed string &str at the end:
trait Foo {
fn display(&self);
}
impl<T> Foo for T where T: AsRef<str> {
fn display(&self) {
println!("{}", self.as_ref());
}
}
fn main() {
"hello".display();
String::from("world").display();
}
If you want an owned String:
trait Foo {
fn display(self);
}
impl<T> Foo for T where T: Into<String> {
fn display(self) {
let s: String = self.into();
println!("{}", s);
}
}
fn main() {
"hello".display();
String::from("world").display();
}

Struct must outlive member reference

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.

Resources