7年前,我选择了自学golang,事实证明我选择对了。目前业界用golang的人越来越多,也越来越卷。于是我就想选择另一门语言了。用了这些年的golang之后,感觉golang在很多场景下还是很难胜任高新能开发;另外,我特别羡慕能做底层开发的同学,比如内核开发、协议栈开发等;因此,我看上了rust,rust号称无gc,甚至还能开发linux内核,还有一些游戏引擎,数据库引擎也是用rust开发的,一听就特别高端是吧。
于是我作为一个新手,开始尝试上手rust,原本准备依照golang的学习路线,先写个博客或者小的web程序,但是,发现rust上手太难。于是降低了上手的要求,用rust重写了一遍我的pinyin项目,项目是将汉字翻译成拼音,支持多音词,需要接入字词库。折腾了许久,终于完成了;这里简单谈一下作为一个rust初学者的感受。
首先,最大一个问题就是局部变量无法在作用域之外使用,这在golang上会自动扩大作用域,无需考虑这些问题。比如,我在一个函数中创建出来的对象,return返回后,发现无法在外部访问,直接报错,实际上该对象在函数结束时已经被销毁。或者说,所在对象发生move,因为他的类型未实现Copy trait。
比如,这种报错经常发生在这么一个场景,我创建了一个config包,辛苦的在里面实现了加载配置文件到一个结构体,当我完成这些之后,希望在另一个mod中引用这个config结构体,便会经常发生这种情况。
use std::fs::File;
use std::io::prelude::*;
use once_cell::sync::Lazy;
#[derive(Deserialize)]
#[derive(Debug)]
struct LasConfig {
pub access_log: Option<String>,
}
#[derive(Deserialize)]
#[derive(Debug)]
struct Conf {
pub las: Option<LasConfig>
}
static global: Lazy<Conf> = Lazy::new(|| {
let file_path = "config.toml";
let mut file = match File::open(file_path) {
Ok(f) => f,
Err(e) => panic!("no such file {} exception:{}", file_path, e)
};
let mut str_val = String::new();
match file.read_to_string(&mut str_val) {
Ok(s) => s,
Err(e) => panic!("Error Reading file: {}", e)
};
toml::from_str(&str_val).unwrap()
});
pub fn get_config() -> Conf {
*global
}
其中*global
的类型的确是Conf
但是却无法通过参数返回。会有如下的报错信息
error[E0507]: cannot move out of dereference of `once_cell::sync::Lazy<Conf>`
--> src/config/cfg.rs:32:5
|
32 | *global
| ^^^^^^^ move occurs because value has type `Conf`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
很明显,这里生成的Conf
类型的global
对象,但是无法直接返回。因为返回的时候发生了move
。
神奇的是,这里get_config()
改成如下这样,就不会有报错了
pub fn get_config() -> &'static Conf {
(*global).borrow()
}
我们从E0507这篇文章中可以看到
the nothing_is_true method
takes the ownership of self
那么我们这里的报错应该也是*global
在返回的时候,将ownership拿走,既然不能拿走,那就改为借用好了。