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() {}
Related
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 have this trait and implementation:
#[async_trait]
pub trait AsyncKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()>;
fn as_any(&self) -> &dyn Any;
}
#[async_trait]
impl AsyncKeyProvider for GoogleKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()> {
{...}
}
fn as_any(&self) -> &dyn Any {
self
}
}
In order to pass it into my handler in actix-web, I'm passing through a GoogleKeyProvider like this:
let key_provider = web::Data::from(Arc::new(GoogleKeyProvider::default()));
let server = HttpServer::new(move || {
App::new()
.app_data(key_provider.clone())
.route("/validate", web::post().to(validate))
})
With the handler doing this:
pub async fn validate(jwt_body: web::Json<JwtBody>, provider: web::Data<Box<dyn AsyncKeyProvider>>) -> impl Responder {
let provider_object: &GoogleKeyProvider = provider.as_any().downcast_ref::<GoogleKeyProvider>().expect("Wasn't a GoogleKeyProvider");
match validate_jwt(&jwt_body.jwt, provider_object).await {
{...}
}
}
validate_jwt then tries to call a method on the provider struct like this:
async fn validate_jwt(jwt: &String, provider: &GoogleKeyProvider) -> Result<bool, Box<dyn std::error::Error>> {
let key_to_use = provider.get_key_async(<thing>).await.unwrap();
}
Which presents me with this error:
error[E0596]: cannot borrow `*provider` as mutable, as it is behind a `&` reference
--> src\routes\validate.rs:48:22
|
48 | let key_to_use = provider.get_key_async(<thing>).await.unwrap();
| ^^^^^^^^ `provider` is a `&` reference, so the data it refers to cannot be borrowed as mutable
As far as I can understand, this is happening because the result of my downcasting is a reference (due to downcast_ref), but I think I'd be wanting the plain GoogleKeyProvider type instead - I'm not sure on that though. I believe the provider needs to be mutable as the values inside it (see below) can change during the lifetime of the provider (it's intended to provide a temporary cache for some keys, and automatically update them if they're out of date)
#[derive(Clone)]
pub struct GoogleKeyProvider {
cached: Option<JwkSet>,
expiration_time: Instant,
}
I'm not sure how to get this working with downcasting, though. Is anyone able to help me see where I've gone wrong?
You have to choice if get_key_async update somme thing at the struct.
The simple code below show you the error
trait Atrait {
fn afn(&mut self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&mut self) -> i32 {
2
}
}
fn main()
{
// test should be mutable
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
This work because afn(self) is not declared mutable afn(&mut self)
trait Atrait {
fn afn(&self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&self) -> i32 {
2
}
}
fn main()
{
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
I have a trait with a couple of implementations, and I want to return the object so I can chain calls.
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> RequestInfo {
self
}
}
struct LoggedOut {}
impl LoggedOut {
fn new() -> Box<RequestInfo> {
Box::new(LoggedOut {})
}
}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {
false
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> Box<RequestInfo> {
Box::new(LoggedIn { output: Vec::new() })
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {
true
}
fn put(&mut self, string: String) -> impl RequestInfo {
self.output.push(string);
self
}
}
fn main() {
let mut info = LoggedIn::new();
info.put("abc".to_string()).put("def".to_string());
}
I get errors:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/main.rs:32:42
|
32 | fn put(&mut self, string: String) -> impl RequestInfo {
| ^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:4:9
|
3 | fn put(&mut self, string: String) -> RequestInfo {
| ----------- expected `(dyn RequestInfo + 'static)` because of return type
4 | self
| ^^^^ expected trait RequestInfo, found &mut Self
|
= note: expected type `(dyn RequestInfo + 'static)`
found type `&mut Self`
error[E0277]: the size for values of type `(dyn RequestInfo + 'static)` cannot be known at compilation time
--> src/main.rs:3:42
|
3 | fn put(&mut self, string: String) -> RequestInfo {
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn RequestInfo + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: the return type of a function must have a statically known size
The only thing that might work is to Box self, like I do in the new() functions, but I don't want to create any extra code by chaining... which is really just a convenience anyway.
Returning &mut Self and using Box<impl RequestInfo> almost works.... except that I have a function that returns either a LoggedIn object or a LoggedOut object, so here's revised code:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self {
self
}
}
struct LoggedOut {}
impl LoggedOut {
fn new() -> Box<impl RequestInfo> {
Box::new(LoggedOut {})
}
}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {
false
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> Box<impl RequestInfo> {
Box::new(LoggedIn { output: Vec::new() })
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {
true
}
fn put(&mut self, string: String) -> &mut Self {
self.output.push(string);
self
}
}
fn get(flag: bool) -> Box<impl RequestInfo> {
if flag {
return LoggedIn::new();
}
LoggedOut::new()
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
And it gives the following error (earlier in the function it returned a LoggedIn object):
error[E0308]: mismatched types
--> src/main.rs:42:5
|
42 | LoggedOut::new()
| ^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
|
= note: expected type `std::boxed::Box<impl RequestInfo>` (opaque type)
found type `std::boxed::Box<impl RequestInfo>` (opaque type)
I gave this some more thought and you can disregard my previous answer. That solution is unnecessarily complex. I got way to focused on returning &mut Self from put, even though that wasn't asked for at all. You can just return &mut RequestInfo from your put method and you're fine. The only price you pay is that you can't have a default implementation for put anymore.
pub trait RequestInfo {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo;
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
self
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
self.output.push(string);
self
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(false);
info.put("abc".to_string()).put("def".to_string());
}
And now to the final step: You will have noticed that traits with methods that return Self can not be used as trait objects. That link has a solution to your problem: mark that method with where Self: Sized, so it doesn't appear on your trait object. But then you can't do your chaining with trait objects. This can be solved by implementing the method on Box<dyn RequestInfo> – which is not a trait object, but a Box. So, putting this all together:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self
where Self: Sized {
self.put_internal(string);
self
}
fn put_internal(&mut self, string: String) {}
}
impl RequestInfo for Box<dyn RequestInfo> {
fn logged_in(&self) -> bool {
self.as_ref().logged_in()
}
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {false}
}
struct LoggedIn {output: Vec<String>}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {true}
fn put_internal(&mut self, string: String) {
self.output.push(string);
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
You will have to decide if all of this is worth it for some chaining.
I have a data structure like this:
struct R {
hmhs: HashMap<i64, HashSet<i64>>,
}
impl R {
fn hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
if let None = self.hmhs.get(&0) {
self.hmhs.insert(0, HashSet::new());
}
self.hmhs.get_mut(&0).unwrap()
}
fn iter_for_hmhs<'a>(&'a mut self) -> impl Iterator<Item = &'a i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
This seems to work, but all the methods require a mutable
reference to self which is unfortunate. I tried to give
interior mutability a go:
struct S {
hmhs: RefCell<HashMap<i64, HashSet<i64>>>,
}
impl S {
fn hs_for_hmhs(&self) -> &HashSet<i64> {
if let None = self.hmhs.borrow().get(&0) {
self.hmhs.borrow_mut().insert(0, HashSet::new());
}
self.hmhs.borrow_mut().get_mut(&0).unwrap()
}
fn iter_for_hmhs(&mut self) -> impl Iterator<Item = &i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
However, I constantly seem to hit problems. Mostly some variety of How do I return a reference to something inside a RefCell without breaking encapsulation?
I have tried lots of variants here, but I am missing something
fundamental in my understanding. Is there a way of achieving what I
want?
Complete Code:
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
struct R {
hmhs: HashMap<i64, HashSet<i64>>,
}
impl R {
fn hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
if let None = self.hmhs.get(&0) {
self.hmhs.insert(0, HashSet::new());
}
self.hmhs.get_mut(&0).unwrap()
}
fn iter_for_hmhs<'a>(&'a mut self) -> impl Iterator<Item = &'a i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
struct S {
hmhs: RefCell<HashMap<i64, HashSet<i64>>>,
}
impl S {
fn hs_for_hmhs(&self) -> &mut HashSet<i64> {
if let None = self.hmhs.borrow().get(&0) {
self.hmhs.borrow_mut().insert(0, HashSet::new());
}
self.hmhs.borrow_mut().get_mut(&0).unwrap()
}
fn iter_for_hmhs(&self) -> impl Iterator<Item = &i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
fn main() {}
Compiler Message:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:36:9
|
36 | self.hmhs.borrow_mut().get_mut(&0).unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
37 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 31:5...
--> src/main.rs:31:5
|
31 | / fn hs_for_hmhs(&self) -> &mut HashSet<i64> {
32 | | if let None = self.hmhs.borrow().get(&0) {
33 | | self.hmhs.borrow_mut().insert(0, HashSet::new());
34 | | }
35 | |
36 | | self.hmhs.borrow_mut().get_mut(&0).unwrap()
37 | | }
| |_____^
I found a solution -- extract the HashMap as a raw pointer. This in turn means that I can get to the HashSet without shenanigans including returning a iterator.
I'm happy enough with this as a solution. The unsafe code is small and contained and if I understand the reason why the compiler is complaining without unsafe, it cannot occur in this code, since neither the HashMap nor the HashSet are ever removed or replaced after construction.
That was a lot of effort.
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
struct R {
hmhs: HashMap<i64, HashSet<i64>>,
}
impl R {
fn hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
if let None = self.hmhs.get(&0) {
self.hmhs.insert(0, HashSet::new());
}
self.hmhs.get_mut(&0).unwrap()
}
fn iter_for_hmhs<'a>(&'a mut self) -> impl Iterator<Item = &'a i64> {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.hs_for_hmhs().insert(i)
}
}
struct S {
hmhs: RefCell<HashMap<i64, HashSet<i64>>>,
}
impl S {
fn hs_as_ptr(&self) -> *mut HashMap<i64, HashSet<i64>> {
self.hmhs.borrow_mut().entry(0).or_insert(HashSet::new());
self.hmhs.as_ptr()
}
fn mut_hs_for_hmhs(&mut self) -> &mut HashSet<i64> {
unsafe { (*self.hs_as_ptr()).get_mut(&0).unwrap() }
}
fn hs_for_hmhs(&self) -> &HashSet<i64> {
unsafe { (*self.hs_as_ptr()).get(&0).unwrap() }
}
fn iter_for_hmhs<'a>(&'a self) -> impl Iterator<Item = &'a i64> + 'a {
self.hs_for_hmhs().iter()
}
fn insert_for_hmhs(&mut self, i: i64) -> bool {
self.mut_hs_for_hmhs().insert(i)
}
}
fn main() {
let mut r = R {
hmhs: HashMap::new(),
};
let mut s = S {
hmhs: RefCell::new(HashMap::new()),
};
r.insert_for_hmhs(10);
s.insert_for_hmhs(20);
println!("r next: {:?}", r.iter_for_hmhs().next());
println!("s next: {:?}", s.iter_for_hmhs().next());
}
https://play.rust-lang.org/?gist=3ed1977bdd5f9f82d144fe128f618979&version=stable&mode=debug&edition=2015
I'll try to be as clear as possible. Let's suppose I have:
struct Foo<'a> {
buffer: &'a [u8],
}
impl<'a> Foo<'a> {
fn create_builder() -> FooBuilder {
FooBuilder::new()
}
fn from_slice(slice: &[u8]) -> Foo {
Foo { buffer: slice }
}
}
struct FooBuilder {
in_progress_buffer: Vec<u8>,
}
impl FooBuilder {
fn new() -> FooBuilder {
FooBuilder { in_progress_buffer: Vec::new() }
}
fn push(&mut self, item: u8) {
self.in_progress_buffer.push(item);
}
fn build_foo(self) -> Foo {
Foo { buffer: self.in_progress_buffer }
}
}
fn main() {
// Option1: Gradually construct Foo from FooBuilder
let mut foo_builder = FooBuilder::new();
foo_builder.push(7);
let foo = foo_builder.build_foo();
// Option2: Construct Foo from a slice
let v = vec![7];
let foo2 = Foo::from_slice(&v);
}
This gives a compilation error:
error[E0106]: missing lifetime specifier
--> src/main.rs:28:27
|
28 | fn build_foo(self) -> Foo {
| ^^^ expected lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= help: consider giving it a 'static lifetime
Is this pattern possible? How can I fix the compilation error?
I'm not sure what lifetime specifier to give since in the FooBuilder version, the FooBuilder owns the buffer, and I don't want to force Foo users to keep the FooBuilder in scope for the entire duration Foo is used
You can use std::borrow::Cow; as the docs state:
it can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required
use std::borrow::Cow;
struct Foo<'a> {
buffer: Cow<'a, [u8]>,
}
impl<'a> Foo<'a> {
fn create_builder() -> FooBuilder {
FooBuilder::new()
}
fn from_slice(slice: &[u8]) -> Foo {
Foo { buffer: slice.into() } // note .into()
}
}
struct FooBuilder {
in_progress_buffer: Vec<u8>,
}
impl<'a> FooBuilder {
fn new() -> FooBuilder {
FooBuilder { in_progress_buffer: Vec::new() }
}
fn push(&mut self, item: u8) {
self.in_progress_buffer.push(item);
}
fn build_foo(self) -> Foo<'a> {
Foo { buffer: self.in_progress_buffer.into() } // note .into()
}
}
In addition, you will need to make foo_builder mutable in order to be able to perform push on it.