问题
I am trying to create a struct to manipulate file storage, but after I change the value it can not be used. I'm sure it's about lifetimes, but I do not understand how I can fix this.
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader};
use std::option::Option;
use std::path::Path;
pub struct Storage<'a> {
path_str: &'a str,
file: Option<File>,
}
const LOCKED_STORAGE: Storage<'static> = Storage {
path_str: &"/tmp/bmoneytmp.bms",
file: None,
};
pub fn get_instance() -> Storage<'static> {
if LOCKED_STORAGE.file.is_none() {
LOCKED_STORAGE.init();
}
LOCKED_STORAGE
}
impl Storage<'static> {
// Create a file for store all data, if does not alred exists
fn init(&mut self) {
let path = Path::new(self.path_str);
self.file = match OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
{
Err(e) => panic!("Couldn't create the storage file at {}", e.description()),
Ok(file) => Some(file),
};
if self.file.is_none() {
panic!("Error on init??"); // This line is not called. Ok :)
}
}
// Check if section exists
pub fn check_section(&self, name: String) -> bool {
if self.file.is_none() {
panic!("Error on check??"); // This line is called. :(
}
true
}
}
fn main() {
let storage = get_instance();
storage.check_section("accounts".to_string());
}
playground
This fails:
thread 'main' panicked at 'Error on check??', src/main.rs:48:13
I am trying to use a method to open a file and read this opened file, but in second method the instance of the file is not opened. Using Option<File>
, I change the value with Same
/None
but the variable continues to be None
.
回答1:
When programming, it's a very important skill to learn how to create a Minimal, Complete, and Verifiable example. Here is one for your problem:
const EXAMPLE: Option<i32> = Some(42);
fn main() {
EXAMPLE.take();
println!("{:?}", EXAMPLE);
}
This prints Some(42)
— the value of EXAMPLE
is not changed.
A const
variable has no guarantees about how many instances it will have. The compiler is allowed to have zero, one, or multiple instances of it. Every time you make use of a const
, it's as if you created a brand new value right there, pasting in the definition of the constant:
fn main() {
Some(42).take();
println!("{:?}", Some(42));
}
Instead, you want to create a singleton.
See also:
- What does it mean for a const type in Rust to be inlined?
- Populating a static/const with an environment variable at runtime in Rust
- Why are const atomic variables not updated, but static atomic variables are?
回答2:
Thanks @shepmaster. I am learned much with your answer. But i changed my approach and fix my problem using Mutex global static and lazy_static.
Also i read the article https://bryce.fisher-fleig.org/blog/strategies-for-returning-references-in-rust/index.html and it helped me to understand my error.
My new code:
#[macro_use]
extern crate lazy_static;
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::option::Option;
use std::sync::Mutex;
pub struct Storage {
path_str: String,
file: Option<File>
}
lazy_static! {
pub static ref LOCKED_STORAGE: Mutex<Storage> = Mutex::new(start_storage());
}
fn start_storage() -> Storage {
let mut st = Storage { path_str: "/tmp/bmoneytmp.bms".to_string(), file: None };
st.init();
st
}
impl Storage {
// Create a file for store all data, if does not alred exists
fn init(&mut self) {
let path = Path::new(&self.path_str);
self.file = match OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
{
Err(e) => panic!("Couldn't create the storage file at {}", e.description()),
Ok(file) => Some(file),
};
}
// Check if section exists
pub fn check_section(&self, name: String) -> bool {
let file = match &self.file {
Some(file) => file,
None => panic!("File of storage not opened")
};
for line in BufReader::new(file).lines() {
println!("{}{:?}", name, line); // Working!!
}
true
}
}
fn main() {
// run in your bash before: echo "Row 1" >> /tmp/bmoneytmp.bms
LOCKED_STORAGE.lock().unwrap().check_section("accounts".to_string());
}
You can build this on playground: https://play.rust-lang.org/?gist=bbd47a13910e0f7cda908dc82ba290eb&version=beta&mode=debug&edition=2018
Full code of my project: https://github.com/fernandobatels/blitz-money
Full code of my fix: https://github.com/fernandobatels/blitz-money/blob/9dc04742a57e6cd99742f2400a6245f210521f5d/src/backend/storage.rs https://github.com/fernandobatels/blitz-money/blob/9dc04742a57e6cd99742f2400a6245f210521f5d/src/backend/accounts.rs
来源:https://stackoverflow.com/questions/52469986/why-do-changes-to-a-const-variable-not-persist-between-usages