从高级程序员的角度来看,Rust 基础知识( 五 )

struct Something { var: u8}println!("{:?}", Something { var: 1 });作用域
Trait有作用域,而且与它实现的类型的作用域是独立的 。也就是说,你可以使用一个类型,但无法使用一个trait的实现(例如,如果这个实现来自另外一个库,而不是来自该类型本身) 。你可以use这个实现 。
self
trait中的self指向它实现的类型 。&self是指向 self: &Self 的别名,其中Self表示该类型(上例中的 self: &Dog) 。self也是self: Self的别名,但两者的区别就是后者会移动变量(即消耗该变量,该变量就无法从外部访问了) 。
当函数定义不以self、&self或&mut self开始时(&mut self相当于带有可改变引用的 &self),就是一个静态方法 。Trait依然可以像任何方法一样定义并实现静态方法 。常见的一个静态方法是new,用于创建类型或结构的实例:
impl Something { fn new -> Something { Something { x: 1 } }}...let var = Something::new;

从高级程序员的角度来看,Rust 基础知识

文章插图
指针
指针实际上非常易懂,尽管它来自其他更高级的语言 。我经常会用错 。
&A指向A,使用时只需要确保A存在,即可保证&A存在,因为我们不应该让指针指向不存在的对象 。
Rust会在编译时进行静态检查,确保不会出现上述情况 。它会自动释放超出作用域的变量,并且不允许指针的存活超过变量 。另一个安全保证是,只能有一个可改变的指针 。
也就是说下述代码是错误的:
let a = 1;let b = &a;let c = &mut a;println!("{b}"); // Error! there can only be one mutable pointerc = 1;我们只需要保证原始变量在指针的作用域中一直存在即可 。
在结构中使用指针会有点问题,因为编译器不喜欢这种做法(因为结构的寿命通常比原始变量更长) 。我通常会采用所有权转移或克隆(.clone(),Clone trait的一部分,可以被derived) 。
有时候,一些函数要求只能用指针,不能用所有权转移 。这时,只需在值的前面加上 & (或 &mut)即可 。
something(&a);此外,还有双重、三重等指针,但很少见,而且一般来说只会更难处理 。
你也不需要考虑释放变量的问题,Rust会在超出作用域时自动释放 。
从高级程序员的角度来看,Rust 基础知识

文章插图
命名空间
使用全名就无需导入 。导入只不过是别名 。
std::env::argsuse std::env;env::argsuse std::env::args;args选择多个“命名空间”可以使用{},如:
use std::env::{args, var};也可以重复使用use:
use std::env;use std::env::args;env::var;args还有一点,你也可以在函数内使用use 。这样,如果代码没有被执行,库就不会被导入(即,如果函数没有在代码路径中出现,例如,use了一个测试用的库,而use只写在了测试用例中,那么在正常构建时就不会导入该库) 。
fn test { use std::env; env::var;}但我不推荐在正常的代码路径中这样写,应该使用全局的导入 。
从高级程序员的角度来看,Rust 基础知识

文章插图
可见性
讨论完命名空间之后,我们来讨论一下可见性 。
本质上,默认情况下任何东西都是私有的,只能被它所在的文件访问 。
● trait及其方法
● 结构及其成员
● enum(成员继承enum的可见性,这是合理的,参见Match)
● 函数
● trait的实现依赖于trait和实现该trait的结构,即,只有两者都是公有的,该实现才是公有的 。
要设置为公有(即可以从外部访问),需要使用关键字pub:
pub struct Something { pub letter: char}pub trait CustomTrait { ... }pub fn method {}
从高级程序员的角度来看,Rust 基础知识

文章插图
使用多个文件
有时候我会想念 require("./fire") 。
要想“导入”一个文件,要使用 mod指令 。通过cargo下载的crate会自动导入 。
main.rs
mod my;fn main { my::function; // or use my::function;


推荐阅读