I am trying to create a struct with non-consuming builder pattern like this:
#[derive(Default)]
struct Person {
first_name: String,
last_name: String,
}
impl<'a> Person {
pub fn first_name(&'a mut self, name: &str) -> &'a mut Self {
self.first_name = name.to_owned();
self
}
pub fn last_name(&'a mut self, name: &str) -> &'a mut Self {
self.last_name = name.to_owned();
self
}
pub fn greet(&self) -> String {
format!("{:?} {:?}", self.first_name, self.last_name)
}
pub fn build(self) -> Self {
self
}
}
fn main() {
let person = Person::default()
.first_name("John")
.last_name("Doe")
.build();
let name = person.greet();
}
But when I use build() to get the value back, I get a move error like this:
error[E0507]: cannot move out of a mutable reference
--> builder/src/main.rs:27:18
|
27 | let person = Person::default()
| __________________^
28 | | .first_name("John")
29 | | .last_name("Doe")
30 | | .build();
| |________________^ move occurs because value has type `Person`, which does not implement the `Copy` trait
How can I use a non-consuming builder pattern while ensuring my code can work in multiple lines? Should I ditch the build() method?
I think you should use two struct, a PersonBuilder, and a Person. The PersonBuilder can collect the applicable info and its build method can check whether a complete Person can be built, and if so return a Person by moving its info into a new Person.
Related
I'm having a hard time figuring out the lifetime syntax that I need for the following code, which does not compile. The basic idea is that I'm creating an Abstract Syntax Tree, and each node must have a different type. Some node types must hold a reference to an external value. It's not possible to make this external value an owned type; it's actually a reference to disk file that must be shared by a number of nodes. Here's the code, as simple as I can make it:
trait Node {
fn init(&mut self, my_str: &str);
}
struct NodeParent {
pub children: Vec<Box<dyn Node>>,
}
impl Node for NodeParent {
fn init(&mut self, my_str: &str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl Node for NodeLeaf<'_> {
fn init(&mut self, my_str: &str) {
self.my_str = Some(my_str);
}
}
impl NodeLeaf<'_> {
pub fn new() -> Box<dyn Node> {
Box::new(NodeLeaf { my_str: None })
}
}
pub fn make_ast() {
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let some_string = String::from("foo");
let my_str = some_string.as_str();
parent.init(my_str);
}
The error is:
error: lifetime may not live long enough
--> src/query/lifetime_test.rs:23:9
|
22 | fn init(&mut self, my_str: &str) {
| --------- - let's call the lifetime of this reference `'1`
| |
| has type `&mut NodeLeaf<'2>`
23 | self.my_str = Some(my_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
I know I need some kind of lifetime on &my_str everywhere it appears, but once I start taking the compiler's suggestion to start adding lifetimes here and there they proliferate, and I never get to code that compiles. I've also tried to Rc<>, but the code to make that work eludes me as well.
How do I specify that &my_str outlives the whole Node tree?
Link to the code on Rust Playground
Add a lifetime to Node:
trait Node<'a> {
fn init(&mut self, my_str: &'a str);
}
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a>>>,
}
impl<'a> Node<'a> for NodeParent<'a> {
fn init(&mut self, my_str: &'a str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl<'a> Node<'a> for NodeLeaf<'a> {
fn init(&mut self, my_str: &'a str) {
self.my_str = Some(my_str);
}
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a>> {
Box::new(NodeLeaf { my_str: None })
}
}
But this is not enough, because Box<dyn Node<'a>> is actually Box<dyn Node<'a> + 'static>, that is, it cannot contain any non-'static lifetime. You need to specify that it can contain lifetime 'a:
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a> + 'a>>,
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a> + 'a> {
Box::new(NodeLeaf { my_str: None })
}
}
Now you will get a different error:
error[E0597]: `some_string` does not live long enough
--> src/lib.rs:39:18
|
39 | let my_str = some_string.as_str();
| ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
40 | parent.init(my_str);
41 | }
| -
| |
| `some_string` dropped here while still borrowed
| borrow might be used here, when `parent` is dropped and runs the destructor for type `NodeParent<'_>`
|
= note: values in a scope are dropped in the opposite order they are defined
Because Box<dyn Node> may have an arbitrary destructor, and it may access the stored string, we need to make sure it is still alive when the value is dropped. Do that by moving the string creation before the nodes:
pub fn make_ast() {
let some_string = String::from("foo");
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let my_str = some_string.as_str();
parent.init(my_str);
}
Playground.
I created a library to deal with digraphs: nodes that link (reference counted) to zero or one other nodes (as in linked lists, but in a digraph a node can be linked to by more than one node).
I am trying to use my library to create a list with a current node:
struct ListWithPointer<'a> {
pub nodes: DigraphNodeRef<String>,
pub current_node: Option<&'a mut DigraphNodeRef<String>>,
}
current_node points to a link in the list.
Now I am trying to move current node to the next element of the list (or to the beginning if the list ended):
fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
if this.current_node.is_some() {
this.current_node.iter_mut().for_each(|a| {
(*a).as_rc_mut().iter_mut()
.for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
});
} else {
this.current_node = Some(&mut this.nodes);
}
}
but whatever I do, it fails with an error like:
error[E0500]: closure requires unique access to `this.current_node` but it is already borrowed
--> src/lib.rs:150:51
|
148 | fn next_node<'a>(this: &'a mut ListWithPointer<'a>) {
| -- lifetime `'a` defined here
149 | if this.current_node.is_some() {
150 | this.current_node.iter_mut().for_each(|a| {
| ---------------------------- ^^^ closure construction occurs here
| |
| borrow occurs here
| argument requires that `this.current_node` is borrowed for `'a`
151 | (*a).as_rc_mut().iter_mut()
152 | .for_each(|rc| this.current_node = Some(&mut Arc::get_mut(rc).unwrap().next));
| ----------------- second borrow occurs due to use of `this.current_node` in closure
Help to rewrite without errors.
Here is the library code:
use std::sync::Arc;
#[derive(Clone)]
pub struct DigraphNode<T> {
pub next: DigraphNodeRef<T>, // I made it `pub` to be able `item.next.next()` to remove an item from the middle.
data: T,
}
impl<T> DigraphNode<T> {
fn new(next: DigraphNodeRef<T>, data: T) -> Self {
Self { next, data }
}
}
pub struct DigraphNodeRef<T> {
rc: Option<Arc<DigraphNode<T>>>,
}
impl<T> DigraphNodeRef<T> {
pub fn new() -> Self {
Self {
rc: None
}
}
pub fn from_node(value: DigraphNode<T>) -> Self {
Self::from(Some(Arc::new(value)))
}
pub fn from(rc: Option<Arc<DigraphNode<T>>>) -> Self {
Self {
rc
}
}
pub fn as_rc(&self) -> &Option<Arc<DigraphNode<T>>> {
&self.rc
}
pub fn as_rc_mut(&mut self) -> &mut Option<Arc<DigraphNode<T>>> {
&mut self.rc
}
pub fn is_none(&self) -> bool {
self.rc.is_none()
}
pub fn remove(&mut self) -> bool {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
true
} else {
false
}
}
pub fn prepend(&mut self, value: T) -> Self {
let new_node = DigraphNode::new(self.clone(), value);
let new_node_ref = DigraphNodeRef::from_node(new_node);
*self = new_node_ref.clone();
new_node_ref
}
pub fn node(&self) -> Option<DigraphNode<T>>
where T: Clone
{
self.rc.clone().map(|node| (*node).clone())
}
/// TODO: Should return a reference.
pub fn data(&self) -> Option<T>
where T: Clone
{
self.rc.clone().map(|node| (*node).data.clone())
}
pub fn values(self) -> DigraphNodeValuesIterator<T> {
DigraphNodeValuesIterator {
underlying: self.clone()
}
}
}
impl<T> Clone for DigraphNodeRef<T> {
fn clone(&self) -> Self {
Self { rc: self.rc.clone() }
}
}
impl<T> Iterator for DigraphNodeRef<T> {
type Item = Arc<DigraphNode<T>>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(rc) = self.rc.clone() {
self.rc = rc.next.rc.clone();
Some(rc.clone())
} else {
None
}
}
}
pub struct DigraphNodeValuesIterator<T> {
underlying: DigraphNodeRef<T>,
}
impl<T: Clone> Iterator for DigraphNodeValuesIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.underlying.next().map(|node| node.data.clone())
}
}
In Rust the mutable access is ensured to be exclusive, i.e. if you hold a reference, some other code can't grab a mutable reference.
Problem is this line:
this.current_node.iter_mut().for_each(...)
It grabs a mutable access to current_node, so it can't regain it again down the line.
Not to mention that iterating over Option is a strange decision.
If you want to move current_node to a different place, I'd try to reorganize your code such that reads are separate from writes, and they are performed in a sequence, instead of trying to do it in one go:
// detach the current_node for moving
if let Some(current_node_to_move) = this.current_node.take() {
let new_current_node_ref: &mut ... = ... // find new location logic
new_current_node_ref.replace(current_node_to_move);
} else {
...
}
Here in line 1 it does a write None update to current_node via this, but immediately relinquishes the mutable reference. Line 2 does a read (search), but also grabs a mutable reference to a new location. Line 3 writes to this location.
To get the linked list implementation right, I recommend https://rust-unofficial.github.io/too-many-lists/
I am trying to do simple telegram bot. I have to response some answer for provided questions.
Problem is that I can't use borrowed parts of question (string) to pass through it to db save function.
I've cut my code as mush as possible:
pub enum Answer {
DbCommand(Box<dyn Fn()>),
}
pub fn process(question: &str) -> Answer {
let parts: Vec<&str> = question
.split(" ")
.collect();
let channel = parts.get(1).unwrap();
Answer::DbCommand(Box::new(|| {
save_to_db(channel)
}))
}
pub fn save_to_db(chan: &str) {
// Saving to db
}
Playground
Output is:
error[E0621]: explicit lifetime required in the type of `question`
--> src/lib.rs:12:23
|
5 | pub fn process(question: &str) -> Answer {
| ---- help: add explicit lifetime `'static` to the type of `question`: `&'static str`
...
12 | Answer::DbCommand(Box::new(|| {
| _______________________^
13 | | save_to_db(channel)
14 | | }))
| |______^ lifetime `'static` required
If I add some function lifetime, then I get error E0495. There's not much information on it
split does not allocate anything, it only iterates over the initial string, keeping a reference to it. You need to own the string and move it into the closure:
pub enum Answer {
DbCommand(Box<dyn Fn()>),
}
pub fn process(question: &str) -> Answer {
let channel = question.split(" ").nth(1).unwrap().to_owned();
Answer::DbCommand(Box::new(move || save_to_db(&channel)))
}
pub fn save_to_db(chan: &str) {
// Saving to db
}
By the way, you do not need to collect anything in this case.
If you really don't want to allocate a string, you can make your struct generic over a lifetime, but I think that this would add an unneeded complexity.:
pub enum Answer<'a> {
DbCommand(Box<dyn Fn() + 'a>),
}
pub fn process(question: &str) -> Answer {
let channel = question.split(" ").nth(1).unwrap();
Answer::DbCommand(Box::new(move || save_to_db(channel)))
}
pub fn save_to_db(chan: &str) {
// Saving to db
}
That's because a trait object has an implicit 'static lifetime by default.
My final code looks like this:
pub enum Answer<'a> {
Text(String),
DbCommand(Box<dyn Fn() -> Result<String, Error> + 'a>),
}
pub fn process(question: &str) -> Answer {
let mut parts = question
.split(" ")
.map(str::trim)
.filter(|s| !s.is_empty());
let command = parts.next();
match command {
//...
Some("/subscribe") => {
match parts.next() {
Some(channel) => {
Answer::DbCommand(Box::new(move || {
db::subscribe_to_channel(&channel)
//...
}))
},
None => Answer::Text("Provide channel name".into()),
}
},
_ => Answer::Text("Invalid command.".into()),
}
}
How can I call a method in closure? get_access_token method can set new access token based on self.get_base_url():
fn fetch_access_token(_base_url: &String) -> String {
String::new()
}
fn get_env_url() -> String {
String::new()
}
pub struct App {
pub base_url: Option<String>,
pub access_token: Option<String>,
}
impl App {
pub fn new() -> App {
App {
base_url: None,
access_token: None,
}
}
pub fn get_base_url(&mut self) -> &String {
self.base_url.get_or_insert_with(|| get_env_url())
}
pub fn get_access_token(&mut self) -> &String {
self.access_token
.get_or_insert_with(|| fetch_access_token(self.get_base_url()))
}
}
fn main() {}
error:
Rust 2015
error[E0500]: closure requires unique access to `self` but `self.access_token` is already borrowed
--> src/main.rs:26:33
|
25 | self.access_token
| ----------------- borrow occurs here
26 | .get_or_insert_with(|| fetch_access_token(self.get_base_url()))
| ^^ ---- borrow occurs due to use of `self` in closure
| |
| closure construction occurs here
27 | }
| - borrow ends here
Rust 2018
error[E0501]: cannot borrow `self.access_token` as mutable because previous closure requires unique access
--> src/main.rs:25:9
|
25 | / self.access_token
26 | | .get_or_insert_with(|| fetch_access_token(self.get_base_url()))
| |______________------------------_--____________________----________________^ second borrow occurs here
| | | |
| | | first borrow occurs due to use of `self` in closure
| | closure construction occurs here
| first borrow later used by call
error[E0500]: closure requires unique access to `self` but it is already borrowed
--> src/main.rs:26:33
|
24 | pub fn get_access_token(&mut self) -> &String {
| - let's call the lifetime of this reference `'1`
25 | self.access_token
| -----------------
| |
| _________borrow occurs here
| |
26 | | .get_or_insert_with(|| fetch_access_token(self.get_base_url()))
| |_________________________________^^____________________----________________- returning this value requires that `self.access_token` is borrowed for `'1`
| | |
| | second borrow occurs due to use of `self` in closure
| closure construction occurs here
Split your data and methods into smaller components, then you can take disjoint borrows to various components on self:
fn fetch_access_token(_base_url: &str) -> String { String::new() }
fn get_env_url() -> String { String::new() }
#[derive(Default)]
struct BaseUrl(Option<String>);
impl BaseUrl {
fn get(&mut self) -> &str {
self.0.get_or_insert_with(|| get_env_url())
}
}
#[derive(Default)]
struct App {
base_url: BaseUrl,
access_token: Option<String>,
}
impl App {
fn new() -> App {
App::default()
}
fn get_access_token(&mut self) -> &str {
let base_url = &mut self.base_url;
self.access_token
.get_or_insert_with(|| fetch_access_token(base_url.get()))
}
}
fn main() {}
You can go further and do this for both values:
fn fetch_access_token(_base_url: &str) -> String { String::new() }
fn get_env_url() -> String { String::new() }
#[derive(Default)]
struct BaseUrl(Option<String>);
impl BaseUrl {
fn get(&mut self) -> &str {
self.0.get_or_insert_with(|| get_env_url())
}
}
#[derive(Default)]
struct AccessToken(Option<String>);
impl AccessToken {
fn get(&mut self, base_url: &str) -> &str {
self.0.get_or_insert_with(|| fetch_access_token(base_url))
}
}
#[derive(Default)]
struct App {
base_url: BaseUrl,
access_token: AccessToken,
}
impl App {
fn new() -> App {
App::default()
}
fn get_access_token(&mut self) -> &str {
let base_url = self.base_url.get();
self.access_token.get(base_url)
}
}
fn main() {}
Which lets you see that you can abstract out common functionality:
fn fetch_access_token(_base_url: &str) -> String { String::new() }
fn get_env_url() -> String { String::new() }
#[derive(Default)]
struct StringCache(Option<String>);
impl StringCache {
fn get<F>(&mut self, f: F) -> &str
where
F: FnOnce() -> String,
{
self.0.get_or_insert_with(f)
}
}
#[derive(Default)]
struct App {
base_url: StringCache,
access_token: StringCache,
}
impl App {
fn new() -> App {
App::default()
}
fn get_access_token(&mut self) -> &str {
let base_url = self.base_url.get(get_env_url);
self.access_token.get(|| fetch_access_token(base_url))
}
}
fn main() {}
And then you realize the abstraction can be made generic:
fn fetch_access_token(_base_url: &str) -> String { String::new() }
fn get_env_url() -> String { String::new() }
#[derive(Default)]
struct Cache<T>(Option<T>);
impl<T> Cache<T> {
fn get<F>(&mut self, f: F) -> &T
where
F: FnOnce() -> T,
{
self.0.get_or_insert_with(f)
}
}
#[derive(Default)]
struct App {
base_url: Cache<String>,
access_token: Cache<String>,
}
impl App {
fn new() -> App {
App::default()
}
fn get_access_token(&mut self) -> &str {
let base_url = self.base_url.get(get_env_url);
self.access_token.get(|| fetch_access_token(base_url))
}
}
fn main() {}
See also:
Borrowing references to attributes in a struct
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec) or Box (&Box) as a function argument?
The Rust Programming Language chapter on closures, which creates this caching struct as part of the exercises.
The closure passed to the get_or_insert_with method in Option<T> is of type FnOnce - it thus consumes or moves the captured variables. In this case self is captured because of the usage of self.get_base_url() in the closure. However, since self is already borrowed, the closure cannot consume or move the value of self for unique access.
This can be circumvented by using the get_or_insert method, but it will require you to perform the potentially expensive operation of fetching the access token every time get_access_token is called regardless of whether access_token is None or not.
I'd use something like this instead:
Playground
fn fetch_access_token(base_url: &str) -> Result<String, ()> {
let _url = format!("{}/v3/auth/token", base_url);
// ...
let token = String::from("test token");
Ok(token)
}
fn get_env_url() -> String {
String::from("http://www.test.com")
}
pub struct App {
// private fields!
base_url: String,
access_token: Option<String>,
}
impl App {
pub fn new() -> App {
App {
base_url: get_env_url(),
access_token: None,
}
}
/// set new base url; clears cached access token
pub fn set_base_url(&mut self, base_url: String) {
self.base_url = base_url;
self.access_token = None;
}
pub fn get_base_url(&self) -> &str {
&self.base_url
}
/// retrieve (possibly cached) access token. tries again if previous attempt failed.
pub fn retrieve_access_token(&mut self) -> Result<&str, ()> {
if self.access_token.is_none() {
self.access_token = Some(fetch_access_token(&self.base_url)?);
}
Ok(self.access_token.as_ref().unwrap())
}
}
fn main() {
let mut app = App::new();
println!("{}", app.retrieve_access_token().unwrap());
}
This has been provided as an answer elsewhere. But, in 2022, you'll probably have a better time using Rc<Self> or Arc<Self> and cloning via Rc::clone(&self) or Arc::clone(&self). Check this out for the official docs on self receiver types.
fn fetch_access_token(_base_url: &String) -> String {
String::new()
}
fn get_env_url() -> String {
String::new()
}
pub struct App {
pub base_url: Option<String>,
pub access_token: Option<String>,
}
impl App {
pub fn new() -> App {
App {
base_url: None,
access_token: None,
}
}
pub fn get_base_url(self : Rc<Self>) -> &String {
let me = Rc::clone(&self);
me.base_url.get_or_insert_with(|| get_env_url())
}
pub fn get_access_token(self : Rc<Self>) -> &String {
let me = Rc::clone(&self);
let other_me = Rc::clone(&self);
me.access_token
.get_or_insert_with(|| fetch_access_token(other_me.get_*))
}
}
fn main() {}
It seems that if you borrow a reference to a struct field, the whole struct is considered borrowed. I've managed to isolate and example of what I want to do. I just want to get a "read-only" reference to a field in B to obtain some data and then modify another field of B. Is there a idiomatic Rust way to do this?
struct A {
i: i32,
}
struct B {
j: i32,
a: Box<A>,
}
impl B {
fn get<'a>(&'a mut self) -> &'a A {
&*self.a
}
fn set(&mut self, j: i32) {
self.j = j
}
}
fn foo(a: &A) -> i32 {
a.i + 1
}
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let a_ref = b.get();
b.set(foo(a_ref));
}
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> src/main.rs:27:5
|
26 | let a_ref = b.get();
| - first mutable borrow occurs here
27 | b.set(foo(a_ref));
| ^ second mutable borrow occurs here
28 | }
| - first borrow ends here
It's a feature of the language. From the compiler point of view, there is no way for it to know that it's safe to call your set() function while a is borrowed via get().
Your get() function borrows b mutably, and returns a reference, thus b will remain borrowed until this reference goes out of scope.
You have several way of handling this:
Separate your two fields into two different structs
Move the code which needs to access both attribute inside a method of B
Make your attributes public, you will thus be able to directly get references to them
Compute the new value before setting it, like this:
fn main() {
let a = Box::new(A { i: 47 });
let mut b = B { a: a, j: 1 };
let newval = {
let a_ref = b.get();
foo(a_ref)
};
b.set(newval);
}
Expanding a bit on Levans' answer
Move the code which needs to access both attribute inside a method of B
That might look like this at a first pass:
impl B {
fn do_thing(&mut self) {
self.j = self.a.foo()
}
}
However, this hard-codes the call to foo. You could also accept a closure to allow this to be more flexible:
impl B {
fn update_j_with_a<F>(&mut self, f: F)
where
F: FnOnce(&mut A) -> i32,
{
self.j = f(&mut self.a)
}
}
// ...
b.update_j_with_a(|a| a.foo())
Separate your two fields into two different structs
This is also applicable when you have borrowed two disjoint subsets of attributes. For example:
struct A {
description: String,
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.build_description()
// cannot borrow `*self` as immutable because `self.description` is also borrowed as mutable
}
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
Can be changed into
struct A {
description: String,
info: Info,
}
struct Info {
name: String,
age: u8,
money: i32,
}
impl A {
fn update_description(&mut self) {
let description = &mut self.description;
*description = self.info.build_description()
}
}
impl Info {
fn build_description(&self) -> String {
format!(
"{} is {} years old and has {} money",
self.name,
self.age,
self.money
)
}
}
fn main() {}
You can combine these two steps (and I'd say that it's better practice) and move the method onto the inner struct.