Get mutable reference to an item in trait objects collection - rust

To play around with Rust, I'm trying to get the following code working (playground, please don't mind the commented blocks, they are for further investigations).
Basically I would like to store in a collection several items of several types implementing a common trait. I can't use an enum because I want the user to implement the trait for more types, so I use trait objects.
I want, after its insertion in the collection, to get a mutable reference to the item, so that the user can use it independently from the fact that it's stored in a collection.
The following code gives me two errors that I have no idea how to solve.
use std::any::Any;
// Trait needed to represent an Animal, with as_any() method to support downcasting
trait Animal {
fn as_any(&self) -> &dyn Any;
fn feed(&mut self);
fn is_fed(&self) -> bool;
}
// Realization of Animal for a dog
struct Dog {
is_fed: bool
}
impl Animal for Dog {
fn as_any(&self) -> &dyn Any {
self
}
fn feed(&mut self) {
self.is_fed = true;
}
fn is_fed(&self) -> bool {
self.is_fed
}
}
// Realization of Animal for a cat
struct Cat {
is_fed: bool
}
impl Animal for Cat {
fn as_any(&self) -> &dyn Any {
self
}
fn feed(&mut self) {
self.is_fed = true;
}
fn is_fed(&self) -> bool {
self.is_fed
}
}
// Struct to host a list of trait objects implementing the trait Animal
struct Zoo {
animals: Vec<Box<dyn Animal>>
}
impl Zoo {
fn new() -> Zoo {
Zoo{animals: Vec::new()}
}
// Method to append a new animal to the zoo and get a mutable reference to the newly created object
fn host<'a, A: Animal>(&mut self, a: A) -> &mut A {
self.animals.push(Box::new(a));
let pushed_box = self.animals.last_mut().expect("error");
pushed_box.as_any().downcast_mut::<A>().expect("error") // error: cannot borrow data in a `&` reference as mutable
}
}
fn main()
{
let mut zoo = Zoo::new();
zoo.host(Dog{is_fed:false});
let cat = zoo.host(Cat{is_fed:false});
zoo.host(Cat{is_fed:false});
zoo.host(Dog{is_fed:false});
zoo.host(Cat{is_fed:false});
let dog = zoo.host(Dog{is_fed:false});
zoo.host(Cat{is_fed:false}); // error : cannot borrow `zoo` as mutable more than once at a time
dog.feed();
}

You can use Rc<RefCell<dyn Animal>> for the collection.
struct Zoo {
animals: Vec<std::rc::Rc<RefCell<dyn Animal>>>,
}
impl Zoo {
fn new() -> Zoo {
Zoo{animals: Vec::new()}
}
fn host<A: Animal + 'static>(&mut self, a: A) -> std::rc::Rc<RefCell<dyn Animal>> {
self.animals.push(std::rc::Rc::new(RefCell::new(a)));
let pushed_box = self.animals.last_mut().expect("error");
pushed_box.clone()
}
}
and use borrow_mut() to get mutable reference to an animal. Or try_borrow_mut() to make sure that the code won't panic if another borrow exists for the same animal.
fn main()
{
let mut zoo = Zoo::new();
zoo.host(Dog{is_fed:false});
let cat = zoo.host(Cat{is_fed:false});
zoo.host(Cat{is_fed:false});
zoo.host(Dog{is_fed:false});
zoo.host(Cat{is_fed:false});
let dog = zoo.host(Dog{is_fed:false});
zoo.host(Cat{is_fed:false});
dog.borrow_mut().feed();
}

Using
fn host<A: Animal + 'static>(&mut self, a: A) -> &mut (dyn Animal + 'static) {
self.animals.push(Box::new(a));
let pushed_box = self.animals.last_mut().expect("error");
pushed_box.as_mut()
}
will fix the first error. You're basically telling the compiler that A will own all the data or only have static references.
You can't return an A because self.animals doesn't consist of only A which at this point is a concrete type.
The second error arises because you keep the reference to dog around till after you edited zoo again.
At that point the whole animals Vec could have moved somewhere else and thus dog is no longer valid.

Related

Assigning proper lifetimes to associated types

I am designing code that should be generic over a trait Atom, that contains many associated types that logically belong together. In the simplified example below, which concerns representing a mathematical expression, there is one variant that gives a 'view' of a Pow and an owned version of a Pow. In actuality, there will be many more variants, such as Var and OwnedVar, Function and OwnedFunction, etc.
Since some traits deal with borrowed data, I added lifetimes and this makes the code below not compile:
pub trait Atom {
// imagine more variants here
type P<'a>: Pow<'a, R = Self>;
type OP: OwnedPow<R = Self>;
}
pub trait Pow<'a> {
type R: Atom;
fn get_base(&self) -> AtomView<Self::R>;
}
pub trait OwnedPow {
type R: Atom;
fn to_view<'a>(&'a self) -> AtomView<Self::R>;
}
pub enum AtomView<'a, R: Atom> {
Pow(R::P<'a>),
}
impl<'a, R: Atom> AtomView<'a, R> {
#[allow(unconditional_recursion, irrefutable_let_patterns)]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if let AtomView::Pow(p2) = other {
let b = p2.get_base();
Some(self.partial_cmp(&b).unwrap())
} else {
None
}
}
}
// concrete implementations
struct Rep;
impl Atom for Rep {
type P<'a> = PowD<'a>;
type OP = OwnedPowD;
}
struct PowD<'a> {
data: &'a [u8],
}
impl<'a> Pow<'a> for PowD<'a> {
type R = Rep;
fn get_base(&self) -> AtomView<Self::R> {
AtomView::Pow(PowD {
data: &self.data[1..],
})
}
}
struct OwnedPowD {
data: Vec<u8>,
}
impl OwnedPow for OwnedPowD {
type R = Rep;
fn to_view<'a>(&'a self) -> AtomView<Rep> {
AtomView::Pow(PowD { data: &self.data })
}
}
fn test<A: OwnedPow>(a: A) {
let _vv = a.to_view();
}
fn main() {
let v = OwnedPowD {
data: vec![1, 2, 3],
};
test(v);
}
This code does not compile:
error[E0621]: explicit lifetime required in the type of `other`
--> src/main.rs:25:21
|
23 | fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
| ----- help: add explicit lifetime `'a` to the type of `other`: `&'a AtomView<'a, R>`
24 | if let AtomView::Pow(p2) = other {
25 | let b = p2.get_base();
| ^^^^^^^^^^^^^ lifetime `'a` required
Of course, giving other the lifetime a is a problem, since other is a locally created variable and thus following the help will not fix the problem. I fail to see why &b seems to have the lifetime &'a b.
The code can be tested on the playground.
I tried fixing this code by dropping many lifetimes in the associated types and traits, but then it seems I need to give Rep a lifetime, and then this Rep<'a> will make its way into OwnedPowD that should have no lifetime (since the data is owned). This attempt can be tried here.
Does anyone know how to assign proper lifetimes?
AtomView has a lifetime argument, which should connect all of the borrowing dependencies together. But you are never specifying it!
pub enum AtomView<'a, R: Atom> {
Pow(R::P<'a>),
}
I was able to make your code compile by changing the trait methods to constrain this lifetime in the "obvious" way in each case:
pub trait Pow<'a> {
type R: Atom;
fn get_base(&self) -> AtomView<'a, Self::R>;
}
pub trait OwnedPow {
type R: Atom;
fn to_view(&self) -> AtomView<'_, Self::R>;
}
And updating the implementations to match:
impl<'a> Pow<'a> for PowD<'a> {
type R = Rep;
fn get_base(&self) -> AtomView<'a, Self::R> {
// just for testing
AtomView::Pow(PowD {
data: &self.data[1..],
})
}
}
impl OwnedPow for OwnedPowD {
type R = Rep;
fn to_view(&self) -> AtomView<'_, Rep> {
AtomView::Pow(PowD { data: &self.data })
}
}

Why is Rust ok with accepting a different struct when implementing the same trait?

I have the following in my tests which compiles and works well:
#[test]
fn zoo_test() {
let mut zoo = Zoo::new();
zoo.add(Monkey::new("m1".to_string()));
zoo.add(Limur::new("l1".to_string()));
assert_eq!(zoo.hi_all::<Monkey>(), vec![
"Monkey m1 says: ah ah ah".to_string(),
"Limur l1 says: yo".to_string()
]);
}
However, I'm a bit confused why zoo.hi_all::<Monkey>() works since it could be either monkey or limur. In other words I don't understand why it works for limur, or am I doing this wrong?
Edit: Here's the code I'm using for src/zoo.rs:
pub mod animal;
pub mod monkey;
pub mod limur;
use std::collections::VecDeque;
use animal::Animal;
pub struct Zoo<'a> {
list: VecDeque<Box<dyn Animal + 'a>>,
}
impl<'a> Zoo<'a> {
pub fn new() -> Zoo<'a> {
Zoo {
list: VecDeque::new(),
}
}
pub fn add<T>(&mut self, animal: T)
where
T: Animal + 'a,
{
self.list.push_back(Box::new(animal));
}
pub fn hi_all<T>(&self) -> Vec<String>
where
T: Animal + 'a,
{
let mut hi: Vec<String> = vec![];
for animal in &self.list {
if let Some(what) = animal.says() {
hi.push(what);
}
}
hi
}
}
The type variable T is declared in the type of this function:
pub fn hi_all<T>(&self) -> Vec<String>
where
T: Animal + 'a,
{
let mut hi: Vec<String> = vec![];
for animal in &self.list {
if let Some(what) = animal.says() {
hi.push(what);
}
}
hi
}
but is never actually used in the function's body! Removing that constraint will have no impact because there is no variable of type T mentioned in the function.
In fact, it never could be used in any practical way, because the elements of the VecDeque are of a specific concrete type, Box<dyn Animal> whereas, from the perspective of code inside the function, T could be any type that implements Animal.
If you need to filter the animals by type then I suggest you use an enum instead of trait objects, so you can discriminate on the enum variant.

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>)

Is it possible to use `impl Trait` as a function's return type in a trait definition?

Is it at all possible to define functions inside of traits as having impl Trait return types? I want to create a trait that can be implemented by multiple structs so that the new() functions of all of them returns an object that they can all be used in the same way without having to write code specific to each one.
trait A {
fn new() -> impl A;
}
However, I get the following error:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/lib.rs:2:17
|
2 | fn new() -> impl A;
| ^^^^^^
Is this a limitation of the current implementation of impl Trait or am I using it wrong?
As trentcl mentions, you cannot currently place impl Trait in the return position of a trait method.
From RFC 1522:
impl Trait may only be written within the return type of a freestanding or inherent-impl function, not in trait definitions or any non-return type position. They may also not appear in the return type of closure traits or function pointers, unless these are themselves part of a legal return type.
Eventually, we will want to allow the feature to be used within traits [...]
For now, you must use a boxed trait object:
trait A {
fn new() -> Box<dyn A>;
}
See also:
Is it possible to have a constructor function in a trait?
Why can a trait not construct itself?
How do I return an instance of a trait from a method?
Nightly only
If you wish to use unstable nightly features, you can use existential types (RFC 2071):
// 1.67.0-nightly (2022-11-13 e631891f7ad40eac3ef5)
#![feature(type_alias_impl_trait)]
#![feature(return_position_impl_trait_in_trait)]
trait FromTheFuture {
type Iter: Iterator<Item = u8>;
fn returns_associated_type(&self) -> Self::Iter;
// Needs `return_position_impl_trait_in_trait`
fn returns_impl_trait(&self) -> impl Iterator<Item = u16>;
}
impl FromTheFuture for u8 {
// Needs `type_alias_impl_trait`
type Iter = impl Iterator<Item = u8>;
fn returns_associated_type(&self) -> Self::Iter {
std::iter::repeat(*self).take(*self as usize)
}
fn returns_impl_trait(&self) -> impl Iterator<Item = u16> {
Some((*self).into()).into_iter()
}
}
fn main() {
for v in 7.returns_associated_type() {
println!("type_alias_impl_trait: {v}");
}
for v in 7.returns_impl_trait() {
println!("return_position_impl_trait_in_trait: {v}");
}
}
If you only need to return the specific type for which the trait is currently being implemented, you may be looking for Self.
trait A {
fn new() -> Self;
}
For example, this will compile:
trait A {
fn new() -> Self;
}
struct Person;
impl A for Person {
fn new() -> Person {
Person
}
}
Or, a fuller example, demonstrating using the trait:
trait A {
fn new<S: Into<String>>(name: S) -> Self;
fn get_name(&self) -> String;
}
struct Person {
name: String
}
impl A for Person {
fn new<S: Into<String>>(name: S) -> Person {
Person { name: name.into() }
}
fn get_name(&self) -> String {
self.name.clone()
}
}
struct Pet {
name: String
}
impl A for Pet {
fn new<S: Into<String>>(name: S) -> Pet {
Pet { name: name.into() }
}
fn get_name(&self) -> String {
self.name.clone()
}
}
fn main() {
let person = Person::new("Simon");
let pet = Pet::new("Buddy");
println!("{}'s pets name is {}", get_name(&person), get_name(&pet));
}
fn get_name<T: A>(a: &T) -> String {
a.get_name()
}
Playground
As a side note.. I have used String here in favor of &str references.. to reduce the need for explicit lifetimes and potentially a loss of focus on the question at hand. I believe it's generally the convention to return a &str reference when borrowing the content and that seems appropriate here.. however I didn't want to distract from the actual example too much.
You can get something similar even in the case where it's not returning Self by using an associated type and explicitly naming the return type:
trait B {}
struct C;
impl B for C {}
trait A {
type FReturn: B;
fn f() -> Self::FReturn;
}
struct Person;
impl A for Person {
type FReturn = C;
fn f() -> C {
C
}
}
Fairly new to Rust, so may need checking.
You could parametrise over the return type. This has limits, but they're less restrictive than simply returning Self.
trait A<T> where T: A<T> {
fn new() -> T;
}
// return a Self type
struct St1;
impl A<St1> for St1 {
fn new() -> St1 { St1 }
}
// return a different type
struct St2;
impl A<St1> for St2 {
fn new() -> St1 { St1 }
}
// won't compile as u32 doesn't implement A<u32>
struct St3;
impl A<u32> for St3 {
fn new() -> u32 { 0 }
}
The limit in this case is that you can only return a type T that implements A<T>. Here, St1 implements A<St1>, so it's OK for St2 to impl A<St2>. However, it wouldn't work with, for example,
impl A<St1> for St2 ...
impl A<St2> for St1 ...
For that you'd need to restrict the types further, with e.g.
trait A<T, U> where U: A<T, U>, T: A<U, T> {
fn new() -> T;
}
but I'm struggling to get my head round this last one.

Specifying lifetimes when using the factory pattern in Rust

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

Resources