I'm trying to implement a simple builder but struggling with lifetimes. The following is giving error: borrowed value does not live long enough. This question seems similar. If I store t in a mutable variable and then call s and finalize it works, but I want to get the one liner to work. What am I doing wrong?
struct Type<'a> {
s: &'a String,
}
struct TypeBuilder {
s: String,
}
impl TypeBuilder {
fn new() -> TypeBuilder {
TypeBuilder { s: "".to_string() }
}
fn s(&mut self, s: String) -> &mut TypeBuilder {
self.s = s;
self
}
fn finalize(&self) -> Type {
Type { s: &self.s }
}
}
fn main() {
let t = TypeBuilder::new()
.s("a".to_string())
.finalize();
println!("string: {}", t.s);
}
The problem is that you're creating Type with a string slice based on a String from TypeBuilder, but TypeBuilder instance created with new() is destroyed immediately in the same let statement, so if this was allowed, the string slice would became dangling. And that's why it works when you store TypeBuilder in a variable first.
The problem with your approach to the builder is that the builder is the owner of data for the value it builds: Type references the contents of TypeBuilder. This means that Type instances are always tied to TypeBuilder instances, and you just cannot create Type and drop TypeBuilder. However, this is really unnatural - builders are usually transient objects which are only necessary during construction.
Consequently, in order for the builder pattern to work correctly your Type must become the owner of the data:
struct Type {
s: String,
}
Then the builder should be passed by value and then consumed by finalize():
impl TypeBuilder {
fn new() -> TypeBuilder {
TypeBuilder { s: "".to_string() }
}
fn s(mut self, s: String) -> TypeBuilder {
self.s = s;
self
}
fn finalize(self) -> Type {
Type { s: self.s }
}
}
This way your building code should work exactly as it is.
Related
From https://doc.rust-lang.org/rust-by-example/trait/dyn.html, as known, the dyn trait's size is not known when compiling, so we can not use it as a return value. But when can create a reference and put it in box, the box has fixed size.
But I met a problem, how can I box a tait which has an interface to consume it.
#[tokio::test]
async fn test_dyn_trait() {
trait Consume {
fn usage(self) -> String;
}
trait Refer {
fn usage(&self) -> String;
}
struct Man {
name: String,
}
impl Consume for Man {
fn usage(self) -> String {
let Man { name } = self;
return name;
}
}
impl Refer for Man {
fn usage(&self) -> String {
return self.name.clone();
}
}
let a: Box<dyn Consume> = Box::new(Man {
name: "aaron".to_string(),
});
let b: Box<dyn Refer> = Box::new(Man {
name: "aaron".to_string(),
});
println!("a: {}", a.usage()); // cannot move a value of type dyn Consume: the size of dyn Consume cannot be statically determined
println!("b: {}", b.usage()); // it is ok
}
This is impossible. Rust has something called object safety, which prevent creating trait objects of traits that have a method that either takes or returns Self (and couple other things).
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();
}
The following code doesn't compile:
trait Phone {
fn call(&self);
}
struct IPhone<'a> {
my_str: &'a str
}
impl<'a> Phone for IPhone<'a> {
fn call(&self) {
print!("{}", self.my_str);
}
}
trait Factory<'a, P: Phone> {
fn new_phone(&self, ms: &'a str) -> P;
}
struct IPhoneFactory;
impl<'a> Factory<'a, IPhone<'a>> for IPhoneFactory {
fn new_phone(&self, ms: &'a str) -> IPhone<'a> {
return IPhone {
my_str: ms
};
}
}
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) {
for _ in 0..10 {
let s = String::new();
let p = f.new_phone(s.as_str());
p.call();
}
}
fn main() {
call_phone(IPhoneFactory);
}
I get the following error:
error: `s` does not live long enough
let p = f.new_phone(s.as_str());
^
note: reference must be valid for the lifetime 'a as defined on the block at 28:53...
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) {
^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 30:30
let s = String::new();
^
I want to be able to have a factory that returns an abstract class, but when that class takes a reference I can't figure out how to specify the lifetime properly.
You're right about that:
There is no reason for the reference to live as long as the factory, it only needs to live as long as the object the factory is creating (the factory itself doesn't store a reference to the string).
But the bound on call_phone says something different
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) { ... }
That code says that there's a single lifetime for the whole factory, which will be used for each phone. You want something different, you want to say that f is a good factory for any lifetime:
fn call_phone<..., F: for<'a> Factory<'a, ...>>(f: F) { ... }
The other problem is that in the Factory trait definition:
trait Factory<'a, P: Phone> {
fn new_phone(&self, ms: &'a str) -> P;
}
There's nothing tying lifetime of P to ms. The trait definition allows the returned phone to outlive the string, which should definitely be forbidden for the IPhone implementation! So, to fix it, we add a lifetime parameter to the Phone trait:
trait Phone<'a> {
fn call(&self);
}
But there's still one problem. We can't really write that signature:
fn call_phone<P: ???, F: for<'a> Factory<'a, P<'a>>(f: F) { ... }
Since we want P to be not a type, but rather a family of types (more precisely, a lifetime → type constructor). Remember, the phone in each iteration of loop has a different type (since the lifetime is a part of a type, and lifetimes in different iterations of loops are different).
Ability to express such a signature is planned for the future Rust, but for now, we have to make a workaround and make the phone associated type of Factory trait:
trait Phone<'a> {
fn call(&self);
}
struct IPhone<'a> {
my_str: &'a str
}
impl<'a> Phone<'a> for IPhone<'a> {
fn call(&self) {
println!("{}", self.my_str);
}
}
trait Factory<'a> {
type Output: Phone<'a>;
fn new_phone(&self, ms: &'a str) -> Self::Output;
}
struct IPhoneFactory;
impl<'a> Factory<'a> for IPhoneFactory {
type Output = IPhone<'a>;
fn new_phone(&self, ms: &'a str) -> IPhone<'a> {
IPhone {
my_str: ms
}
}
}
fn call_phone<F: for<'a> Factory<'a>>(f: F) {
for i in 0..10 {
let s = i.to_string();
let p = f.new_phone(&s);
p.call();
}
}
fn main() {
call_phone(IPhoneFactory);
}
Associated type allows the factory to produce only one kind of product, which is maybe what you wanted. If you want different implementations of Factory to have different Outputs, you can achieve this by using phantom types:
trait Phone<'a> {
type Phantom;
fn call(&self);
}
enum IPhonePhantom {}
struct IPhone<'a> {
my_str: &'a str
}
impl<'a> Phone<'a> for IPhone<'a> {
type Phantom = IPhonePhantom;
fn call(&self) {
println!("{}", self.my_str);
}
}
trait Factory<'a, Selector> {
type Output: Phone<'a, Phantom=Selector>;
fn new_phone(&self, ms: &'a str) -> Self::Output;
}
struct MyFactory;
impl<'a> Factory<'a, IPhonePhantom> for MyFactory {
type Output = IPhone<'a>;
fn new_phone(&self, ms: &'a str) -> IPhone<'a> {
IPhone {
my_str: ms
}
}
}
fn call_phone<Selector, F: for<'a> Factory<'a, Selector>>(f: F) {
for i in 0..10 {
let s = i.to_string();
let p = f.new_phone(&s);
p.call();
}
}
fn main() {
call_phone::<IPhonePhantom, _>(MyFactory);
}
The Phantom associated type on the Phone trait is not strictly necessary, it's only needed to tie the phone type to its phantom type and to make sure Factory implementors don't lie.
Your problem is here:
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F) {
// Factory has a lifetime 'a ----------^
// that is at least as long as the scope of call_phone
for _ in 0..10 {
let s = String::new(); // s is born here
let p = f.new_phone(s.as_str());
// new reference ---^
// new_phone definition requires this to have
// the same lifetime 'a as the Factory
p.call();
}
// s is destroyed here, no references to s can
// still exist
} // F is still alive
One thing you can do is passing the &str as a parameter to call_phone, to make sure the reference lives as long as the function:
fn call_phone<'a, P: Phone, F: Factory<'a, P>>(f: F, s: &'a str) {
for _ in 0..10 {
let p = f.new_phone(s);
p.call();
}
}
fn main() {
call_phone(IPhoneFactory, &"hello");
}
Another one is not working with references, but let your struct IPhone own the String
I am calling a function that takes a &[&str]. As it is more convenient to write ["aa", "bb"], instead of &["aa", "bb"], I decided to add AsRef:
struct Builder<'a> {
s: Option<&'a [&'a str]>,
}
impl<'a> Builder<'a> {
fn new() -> Builder<'a> {
Builder { s: None }
}
fn abc<S>(&mut self, s: S) -> &mut Self
where S: AsRef<[&'a str]> + 'a
{
self.s = Some(s.as_ref());
self
}
fn build(&self) -> u32 {
0
}
}
fn main() {
Builder::new().abc([]).build();
}
(Playground)
But there is a problem with lifetime:
error: `s` does not live long enough
self.s = Some(s.as_ref());
^
note: reference must be valid for the lifetime 'a as defined on the block at 12:4...
{
self.s = Some(s.as_ref());
self
}
note: ...but borrowed value is only valid for the scope of parameters for function at 12:4
{
self.s = Some(s.as_ref());
self
}
The code tries to transfer ownership of the array to the function abc([]), take a reference to the array (s.as_ref()), then it throws away the array, which would leave a pointer to undefined memory. Rust does not allow you to do that.
I did it: self.s = Some(unsafe { std::mem::transmute(s.as_ref()) });
This is a very bad idea. As mentioned above, you now have a reference to an array that no longer exists. That memory is allowed to have anything placed there in the future, and accessing the pointer will, in the best case, cause your program to crash, but could also continue executing but with nonsense data.
Only use unsafe code when you understand all the consequences.
A workaround is to make Builder be generic over S and be the owner of parameter s:
struct Builder<S> {
s: Option<S>,
}
impl<'a> Builder<[&'a str; 0]> {
fn new() -> Self {
Builder { s: None }
}
}
impl<'a, S: AsRef<[&'a str]>> Builder<S> {
fn abc<T: AsRef<[&'a str]>>(self, s: T) -> Builder<T> {
Builder {
// copy other fields, x: self.x, ...
// and replace s
s: Some(s)
}
}
fn print_s(&self) {
// example of using s
if let Some(ref s) = self.s {
println!("{:?}", s.as_ref()); // S::as_ref
} else {
println!("None");
}
}
}
Now abc can be called with different parameter types:
fn main() {
Builder::new().print_s();
Builder::new().abc([]).print_s();
Builder::new().abc(["a", "b"]).print_s();
Builder::new().abc(&["a", "b", "c"]).print_s();
Builder::new().abc(vec!["a"]).print_s();
}
Editor's note: The syntax in this question predates Rust 1.0 and the 1.0-updated syntax generates different errors, but the overall concepts are still the same in Rust 1.0.
I have a struct T with a name field, I'd like to return that string from the name function. I don't want to copy the whole string, just the pointer:
struct T {
name: ~str,
}
impl Node for T {
fn name(&self) -> &str { self.name }
// this doesn't work either (lifetime error)
// fn name(&self) -> &str { let s: &str = self.name; s }
}
trait Node {
fn name(&self) -> &str;
}
Why is this wrong? What is the best way to return an &str from a function?
You have to take a reference to self.name and ensure that the lifetimes of &self and &str are the same:
struct T {
name: String,
}
impl Node for T {
fn name<'a>(&'a self) -> &'a str {
&self.name
}
}
trait Node {
fn name(&self) -> &str;
}
You can also use lifetime elision, as shown in the trait definition. In this case, it automatically ties together the lifetimes of self and the returned &str.
Take a look at these book chapters:
References and borrowing
Lifetime syntax