Rust:变量与常量

Rust 是 静态类型(statically typed)语言,也就是说在编译时就必须知道所有变量的类型。根据值及其使用方式,编译器通常可以推断出我们想要用的类型
在Rust中,每一个值都属于某一个数据类型,告知rust它被指定为何种数据以明确数据处理方式

Rust是静态强类型语言,所有的变量都有严格的编译期语法检查。

1、let变量

rust中使用let关键字声明局部变量,只能在作用域{}内声明定义使用

两种局部变量

不可变局部变量
fn main() {
    let x = 5;  //操作系统给x分配一块空间,并且把5存放到这块空间里面,然后标记这块栈空间是不可用:也就是说从此这块内存只能不能写了
    let  addr = &x as *const i32 as usize;   //操作系统给addr分配了一块只读不写的空间,空间里面存储着x的地址。
    println!("The value of x is:{}, adder is {:X}", x, addr);
    x = 6;  //此处视图去修改x这块已经标记为不可变的内存空间,因此会出错 
    println!("The value of x is:{}, adder is {:X}", x, addr);
}

Rust:变量与常量_第1张图片
规则:Rust使用let声明变量, OS就会将变量绑定到一块存储了value的的内存空间上,并且这块空间只读不写。,也就是说let声明的变量的值是不可以改变的。

可变局部变量

规则:Rust使用let mut声明局部变量, OS会就分配一块存储了value的可读可写的内存空间,也就是说,这个值是可以修改的

fn main() {
    let mut x = 5;//let操作系统给x分配一块栈空间,并且把5存放到这块空间里面,然后标记这块栈空间是mut可读可写:也就是x是可以修改的
//注:let语句在此处引入了一个模式解构功能,不要把let mut看成一个组合,应该把mux x视为一个组合
    let  mut addr = &x as *const i32 as usize; 
    println!("The value of x is:{}, adder is {:X}", x, addr);

     x = 6;  //地址没变但是值变了

    addr = &x as *const i32 as usize; 
    println!("The value of x is:{}, adder is {:X}", x, addr);
}

总结:

  • let声明不可变局部变量,let mut声明可变局部变量。
  • 在Rust中,一般把局部变量的声明初始化叫做“变量绑定”
  • 使用大型数据结构时,适当地使用可变变量,可能比复制和返回新分配的实例更快。对于较小的数据结构,总是创建新实例,采用更偏向函数式的编程风格,可能会使代码更易理解,为可读性而牺牲性能或许是值得的。??

let特性

自动类型推导与类型注解

rust有自动类型推导的功能

let x = 5;
let mut y = 6;
let x = 5u8;  //通过字面量推导
fn main() {
    let play_score = [("jack", 20), ("july", 15), ("lily", 25)];

    let plays:Vec<_> = play_score.iter()
        .map(|&(play, _score)|{
            play
        })
        .collect();

    println!("{:?}", plays) //["jack", "july", "lily"]
}

也可以直接写出变量类型

let x:i32 = 5; //x被绑定为i32类型,它的值是5
let mut y:i32 = 6; 
let x:i32 = 100;   
  • Rust变量声明时:要声明的变量前置,对它的类型描述后置
  • 设计理由:在变量声明中,最重要的是变量本身,而类型只是一个附属的额外描述,并非必不可少的部分。Rust有自动类型推导的功能

1、Rust有自动类型推导功能,但是它仍然是静态类型语言:一个变量的类型必须在编译阶段就确定,而且无法更改

2、Rust只允许"局部变量/全部变量???"进行自动类型推导,不允许函数签名等推导类型
原因:函数签名如果使用自动类型推导,可能导致某个调用的地方使用方式发生变化,它的参数,返回值类型就发生变化,可能导致一系列错误。

变量使用前必须初始化

规则:Rust变量必须先声明后使用
1、如果我们想要使用一个变量,就必须将这个变量名绑定到一个值上。使用变量之前必须初始化

fn main() {
    let x:i32;

    println!("{}", x)  //error[E0381]: borrow of possibly uninitialized variable: `x`
}

2、为什么变量必须初始化之后才能被使用
尝试回答:Rust中,类型没有"默认构造函数",变量没有“默认值”。对于let x:i32; 如果没有显示赋值,它就没有被初始化。不像其他语言,会默认初始化为0

隐藏[覆盖,不建议使用]
fn main() {
    let x = 1;  //作用域:从定义到下一个x
    let  mut addr = &x as *const i32 as usize;
    println!("The value of x is:{}, adder is {:X}", x, addr);

    let x = x + 1;  //OS又重新分配了一个空间,这个空间的名字叫做x
    addr = &x as *const i32 as usize;
    println!("The value of x is:{}, adder is {:X}", x, addr);

    let x = x * 2; //新创建一个叫做x的不可变变量
    addr = &x as *const i32 as usize;
    println!("The value of x is:{}, adder is {:X}", x, addr);
}

Rust:变量与常量_第2张图片
1、当再次使用 let 时,实际上创建了一个新变量,我们可以改变值的类型,但复用这个名字。

fn main(){
    let spaces = "len";  //字符串类型
    let spaces = spaces.len(); //数字类型

    println!("spaces = {}", spaces);  //3
}

2、同一个名字是可以多次绑定不同的值,但不建议这么做,因为它被重新绑定就必须重新确定一下它的定义,这可能会引起程序的混淆不清。
3、什么时候使用变量遮蔽
比如:对一个可变数组初始化[可读写]之后希望这个变量是只读的

fn main() {
    let mut v = vec![1, 2, 3];
    v.push(4);

    let v = v;  //从这里往下,v成了只读变量,可读写变量v已经被遮蔽,无法再访问
    for i in v{
        println!("{}", i)
    }
}

比如:希望修改一个不可变变量

fn main() {
    let  v = vec![1, 2, 3];
    let mut v = v;
    v.push(4);
    println!("{:?}", v)
}

但是还是不建议过度使用,甚至不要使用这个特性【因为我压根儿就没觉得这个有什么优点,当然个人之见】

奇怪的模式解构

let除了声明局部变量外,还具有模式解构的功能

fn main() {
    let (x, z) = (1, 2);
    println!("{}, {}", x, z);
}

上面这个是什么东西,w(゚Д゚)w,据说和模式有关
下面是定义一个元组

fn main() {
    let  y:(i32, i32) = (1, 2);
    println!("{}", y.0);    
}

2、static变量

Rust中使用static关键字声明静态变量

静态局部变量

静态全局变量

3、const常量

规则:声明常量使用 const 关键字而不是 let,并且必须注明值的类型

fn test(){
    const  MIN_POINT:u32 = 1006;  //作用域{}可以访问
    println!("const, MIN_POINT:{}", MIN_POINT)
}

规则:const声明的常量可以在任何作用域中声明,let声明的局部变量只能在{}内声明使用

const MAX_POINT:u32 = 100_100; //作用域:当前文件内
//常量的名称是 MAX_POINTS,值是 100,100

fn test(){
    const  MIN_POINT:u32 = 1006;  //作用域:{}
    println!("const,MAX_POINT:{}; MIN_POINT:{}", MAX_POINT, MIN_POINT)
}
fn main() {
    test();

     println!("const,MAX_POINT:{}", MAX_POINT)
}

规则:常量的初始化表达式一定要是一个编译器常量,不能是运行期值
规则:常量绝对不能使用mut修饰,因为mut是用来声明可变局部变量的。
规则:常量的初始化表达式一定要是一个编译器常量,不能是运行期值
规则:const常量没有类似let局部变量那样的模板匹配功能,不能是运行期值

1、const常量与static静态变量区别

  • 编译器不一定会给const常量分配内存空间,在编译过程中,它很可能会被内联优化。因此,千万不要通过unsafe代码去修改常量的值,这样做是没有意义的。

2、Rust 常量的命名规范是使用下划线分隔的大写字母单词,并且可以在数字字面值中插入下划线来提升可读性

参考:https://kaisery.github.io/trpl-zh-cn/ch03-02-data-types.html
https://kaisery.gitbooks.io/rust-book-chinese/content/content/Primitive%20Types%20%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B.html
《深入浅出Rust》

你可能感兴趣的:(rust)