How to pass through &str lifetime to Box<dyn Fn()> - rust

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()),
}
}

Related

Inserting into a map in a function

Im still trying to wrap my head around lifetimes in rust but ive run into a problem. I have a struct that has a map and im tryign to add to that map in a function. It maps a string id to an object:
pub struct AGVController<'a> {
agv_map: HashMap<&'a str, AGV>
}
impl AGVController<'_> {
// Create a new AGV Controller
pub fn new() -> Self {
Self {
agv_map: HashMap::new()
}
}
// Add a new AGV
pub fn add_agv(&mut self, ip_addr: &str) -> Option<&str> {
let new_agv = AGV::new(ip_addr);
match self.agv_map.get(ip_addr) {
Some(_) => {
let result = format!("AGV with ip address {} already exists", ip_addr);
return Some(result.as_str());
},
None => {
self.agv_map.insert(ip_addr, new_agv);
}
}
return Some("");
}
}
in add new I want to create a new instance and add that to the map. Im getting the following error:
lifetime of reference outlives lifetime of borrowed content...
--> src/agv/agv_controller.rs:58:37
|
58 | self.agv_map.insert(ip_addr, new_agv);
| ^^^^^^^
|
note: ...the reference is valid for the lifetime `'_` as defined here...
--> src/agv/agv_controller.rs:16:20
|
16 | impl AGVController<'_> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime defined here
--> src/agv/agv_controller.rs:50:40
|
50 | pub fn add_agv(&mut self, ip_addr: &str) -> Option<&str> {
| ^^^^
It seems like it is saying that the reference in the map will outlive the reference of the parameter passed in, which is fair I guess.
Can someone explain to me how I add an entry to a map in a function where the key is passed into the function?
This fails because the lifetime of the ip_addr reference is only valid while the add_agv method executes, but it needs to be valid for the 'a in AGVController<'a>. To fix this, add the 'a lifetime to your impl block and use it for this parameter:
impl<'a> AGVController<'a> {
// ...
pub fn add_agv(&mut self, ip_addr: &'a str) -> Option<&str> {
Which brings us to the second problem: you attempt to return a &str to a String that is owned by this function (in result). This is simply impossible; return an Option<String> instead, making the appropriate changes to your return statements.
pub fn add_agv(&mut self, ip_addr: &'a str) -> Option<String> {
return Some(result);
return Some("".to_owned());
(Playground)
Alternatively, consider returning a Result, which is a better way to indicate an operation that can fail:
use std::error::Error;
use std::fmt::{Display, Formatter, Error as FmtError};
#[derive(Debug)]
pub struct DuplicateIPAddress(pub String);
impl Error for DuplicateIPAddress {}
impl Display for DuplicateIPAddress {
fn fmt(&self, w: &mut Formatter) -> Result<(), FmtError> {
write!(w, "Duplicate IP address {}", self.0)
}
}
Now your function can return Result<(), DuplicateIPAddress>:
pub fn add_agv(&mut self, ip_addr: &'a str) -> Result<(), DuplicateIPAddress> {
return Err(DuplicateIPAddress(ip_addr.to_owned()));
return Ok(());
(Playground)

How to downcast mutable structs not as references

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

How do I implement an iterator from a vector of std::Rc<std::RefCell<T>> smart pointers?

I'm trying to understand how to work with interior mutability. This question is strongly related to my previous question.
I have a generic struct Port<T> that owns a Vec<T>. We can "chain" port B to port A so, when reading the content of port A, we are able to read the content of port B. However, this chaining is hidden to port A's reader. That is why I implemented the iter(&self) method:
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<Port<T>>>,
}
impl <T> Port<T> {
pub fn new() -> Self {
Self { values: vec![], ports: vec![] }
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: Rc<Port<T>>) {
if !port.is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports.iter()
.flat_map(|p| Box::new(p.iter()) as Box<dyn Iterator<Item = &T>>)
)
}
pub fn clear(&mut self) {
self.values.clear();
self.ports.clear();
}
}
The application has the following pseudo-code behavior:
create ports
loop:
fill ports with values
chain ports
iterate over ports' values
clear ports
The main function should look like this:
fn main() {
let mut port_a = Rc::new(Port::new());
let mut port_b = Rc::new(Port::new());
loop {
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(port_b.clone());
for val in port_a.iter() {
// read data
};
port_a.clear();
port_b.clear();
}
}
However, the compiler complains:
error[E0596]: cannot borrow data in an `Rc` as mutable
--> src/modeling/port.rs:46:9
|
46 | port_a.add_value(1);
| ^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Port<i32>>`
I've been reading several posts etc., and it seems that I need to work with Rc<RefCell<Port<T>>> to be able to mutate the ports. I changed the implementation of Port<T>:
use std::cell::RefCell;
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<RefCell<Port<T>>>>,
}
impl<T> Port<T> {
// snip
pub fn chain_port(&mut self, port: Rc<RefCell<Port<T>>>) {
if !port.borrow().is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports
.iter()
.flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
)
}
// snip
}
This does not compile either:
error[E0515]: cannot return value referencing temporary value
--> src/modeling/port.rs:35:31
|
35 | .flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
| ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
I think I know what the problem is: p.borrow() returns a reference to the port being chained. We use that reference to create the iterator, but as soon as the function is done, the reference goes out of scope and the iterator is no longer valid.
I have no clue on how to deal with this. I managed to implement the following unsafe method:
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(self.ports.iter().flat_map(|p| {
Box::new(unsafe { (&*p.as_ref().as_ptr()).iter() }) as Box<dyn Iterator<Item = &T>>
}))
}
While this works, it uses unsafe code, and there must be a safe workaround.
I set a playground for more details of my application. The application compiles and outputs the expected result (but uses unsafe code).
You can't modify anything behind an Rc, that's correct. While this might be solved with a RefCell, you don't want to go down that road. You might come into a situation where you'd need to enforce a specific clean() order or similar horrors.
More important: your main is fundamentally flawed, ownership-wise. Take these lines:
let mut port_a = Port::new();
let mut port_b = Port::new();
loop {
// Creates an iummutable borrow of port_b with same lifetime as port_a!
port_a.chain_port(port_b);
// ...
// A mutable borrow of port_b.
// But the immutable borrow from above persists across iterations.
port_b.clear();
// Or, even if you do fancy shenanigans at least until this line.
port_a.clear();
}
To overcome this, just constrain the ports lifetime to one iteration. You currently manually clean them up anyway, so that's already what you're doing conceptually.
Also, I got rid of that recursive iteration, just to simplify things a little more.
#[derive(Clone)]
pub struct Port<'a, T> {
values: Vec<T>,
ports: Vec<&'a Port<'a, T>>,
}
impl<'a, T> Port<'a, T> {
pub fn new() -> Self {
Self {
values: vec![],
ports: vec![],
}
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: &'a Port<T>) {
if !port.is_empty() {
self.ports.push(&port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut port_stack: Vec<&Port<T>> = vec![self];
// Sensible estimate I guess.
let mut values: Vec<&T> = Vec::with_capacity(self.values.len() * (self.ports.len() + 1));
while let Some(port) = port_stack.pop() {
values.append(&mut port.values.iter().collect());
port_stack.extend(port.ports.iter());
}
values.into_iter()
}
}
fn main() {
loop {
let mut port_a = Port::new();
let mut port_b = Port::new();
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(&port_b);
print!("values in port_a: [ ");
for val in port_a.iter() {
print!("{} ", val);
}
println!("]");
}
}

Lifetimes on traits as return values

I would like to hide the actual implementation that is returned from the create function by returning an impl trait as in create_trait(). How could this be done?
trait Names<'a> {
fn names(&'a self) -> &Vec<&'a str>;
}
struct NamesImpl<'b> {
names: Vec<&'b str>,
}
impl<'c> Names<'c> for NamesImpl<'c> {
fn names(&'c self) -> &Vec<&'c str> {
&self.names
}
}
fn create_impl<'i>() -> NamesImpl<'i> {
NamesImpl {
names: vec!["Hello", "world"],
}
}
#[allow(dead_code)]
fn create_trait<'t>() -> impl Names<'t> {
NamesImpl {
names: vec!["Hello", "world"],
}
}
fn main() {
let names_impl = create_impl();
println!("Names: {:?}", names_impl.names());
//This doesn't compile, see error below
let names_trait = create_trait();
println!("Names: {:?}", names_trait.names());
}
I can't wrap my head around the following compile error. Why does it work with create_impl() but not with create_trait()?
error[E0597]: `names_trait` does not live long enough
--> src/main.rs:34:29
|
34 | println!("Names: {:?}", names_trait.names());
| ^^^^^^^^^^^ borrowed value does not live long enough
35 | }
| -
| |
| `names_trait` dropped here while still borrowed
| borrow might be used here, when `names_trait` is dropped and runs the destructor for type `impl Names<'_>`
A general rule of thumb when it comes to using lifetimes in Rust is that if you don't know what you're doing, let the compiler infer the correct lifetimes for you. Once you get more experience, you'll learn when you actually need to use explicit lifetime annotations, but your example is not one of those situations. I was able make it compile by removing all the unnecessary lifetime annotations:
trait Names {
fn names(&self) -> &Vec<&str>;
}
struct NamesImpl<'a> {
names: Vec<&'a str>,
}
impl Names for NamesImpl<'_> {
fn names(&self) -> &Vec<&str> {
&self.names
}
}
fn create_impl() -> NamesImpl<'static> {
NamesImpl { names: vec!["Hello", "world"] }
}
fn create_trait() -> impl Names {
NamesImpl { names: vec!["Hello", "world"] }
}
fn main() {
let names_impl = create_impl();
println!("Names: {:?}", names_impl.names());
// compiles
let names_trait = create_trait();
println!("Names: {:?}", names_trait.names());
}
playground
To determine which lifetime annotations were unnecessary, I started by removing all of them and then only added lifetime annotations back to the areas where the compiler specifically asked me to.
This section in Common Rust Lifetime Misconceptions (Thank you pretzelhammer!) was an eye opener to me. It made mee see that in this construction
trait Names<'a> {
fn names(&'a self) -> &Vec<&'a str>;
}
calling names() will borrow the struct for the rest of its lifetime.
Correcting this in the original code with explicit lifetime annotations is possible, but the result is far from beautiful. I just tried this in an attempt to better understand the 'why'.
trait Names<'a : 'f, 'f> {
fn names(&self) -> &Vec<&'f str>;
}
struct NamesImpl<'b> {
names: Vec<&'b str>,
}
impl <'c : 'f, 'f> Names<'c, 'f> for NamesImpl<'c> {
fn names(&self) -> &Vec<&'f str> {
&self.names
}
}
fn create_impl<'i : 'f, 'f>() -> NamesImpl<'i> {
NamesImpl{names: vec!["Hello", "world"]}
}
#[allow(dead_code)]
fn create_trait<'t : 'f, 'f>() -> impl Names<'t, 'f> {
NamesImpl{names: vec!["Hello", "world"]}
}
fn main() {
let names_impl = create_impl();
println!("Names: {:?}", names_impl.names());
//This compiles
let names_trait = create_trait();
println!("Names: {:?}", names_trait.names());
}
Conclusion: Follow the advice given by Shepmaster

How to use struct self in member method closure

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() {}

Resources