Rust基础类型

 

这篇文章主要就Rust的一些比较特殊的基础概念,如变量、数据类型、控制流等进行简单的讲解。

1、变量

  需要提到的是Rust是一门专注‘安全’,‘高性能’的语言,所以在变量的时候以及其他特性上,和其他语言有较大的差异,Rust是支持类型推导的,但是默认变量是不可变的。

fn main() {
    let x = 5;
    println!("The value of x is: {}",x);
    x = 6; 
    println!("The value of x is: {}",x);  // error : cannot assign twice to immutable variable
}

 有时候可变性变量是非常有用的,变量只是默认不可变,我们可以使用mut来定义一个可变性变量。

fn main() {
    let mut x = 5;
    println!("The value of x is: {}",x);
    x = 6; 
    println!("The value of x is: {}",x);  // error : cannot assign twice to immutable variable
}

  

2. 变量和常量的区别

  不允许改变值的变量,可能会使你想起另一个大部分编程语言都有的概念:常量。 类似于不可变变量,但是还是有些区别,首先不允许对常量使用mut,声明方式使用const,常量可以在任何作用域声明,且不能被其他变量覆盖,统一使用大写。

const MAX_INT:u32 = 1000_000;   // Rust变量命名规则中使用_可以用来分大写单词,并且可以在数字面值中使用提升阅读性

fn main() {
    // let MAX_INT = 200;  // Error 常量不能被覆盖shadowing
    println!("The value of const is:{}",MAX_INT);
}

 

3.字符串、元祖、数组

use std::mem;

fn main() {
    // 元祖 tuple, 元祖类型可以自己推导
    let a = (1, 'q', false);
    let b = (1,('1',true));
    println!("a: {} {} {}",a.0,a.1,a.2);
    // println!("b: {}",b.1); // ERR 因为这里的b.1s是个复杂类型(不单一),需要使用另外的占位符
    println!("b: {:?}", b.1);
    // 格式化输出, size_of_val会输出对应变量的内存大小
    println!("b petty: {:#?} {}",b,mem::size_of_val(&b));

    // 数组,注意和访问元祖的方式不一样
    let xs: [i32;5] = [2,3,4,5,6];
    // 默认情况下:32位占4byte,这里有5个数占20byte
    println!("{} {} {}",xs[0],xs.len(),mem::size_of_val(&xs));

    // 数组的切片
    let xy = &xs[2..4];
    println!("xy: {:?}",xy); // 4 5
    // let xy1: [i32;2] = xs[2..4]; // ERR 不能使用值切割,本质上数组就是字符的切片组合

    // 字符串和字符
    let s = "String";  // 这是字符串 &str
    let ss = String::from("String");

    let s_s = s.to_string();
    println!("{} {}",s_s,ss); //String String

    let h = String::from("hello, ");
    let w = String::from("world");
    let hw = h + &w;
    println!("hw: {} w:{}",hw, w);  // w继续可用
    //let hw1 = h + w;  // 编译不通过,w需要是&str类型

}

  

4、shadowing(隐藏属性)

  我们可以定义一个与之前变量同名的新变量,而新变量会隐藏之前的变量,这意味着使用这个变量时始终会看到最后一个,这也铺垫了以后我们说Rust的所有权概念。

fn main() {
    let x = 5;
    let x = x +1;
    let x = x * 2;

    println!("The value of x is:{}",x);
    let y = {
        let x = 32;
        x   //  不加;h会默认返回x的值
    };

    println!("The value of y is:{}",y);
}

  隐藏与将变量设置为mut是有区别的:

    1、一个变量使用let声明了后,不小心尝试对变量重新赋值时,如果没有使用let,会导致编译失败,通过再次使用let声明我们可以用这个值进行一些计算,返回的还是不可变的变量

    2、mut与单单let的另一个区别是,当再次使用let时,实际上创建了一个新变量,我们可以改变值类型,但复用这个名字。

fn main() {
    let spaces = "     ";
    let spaces = spaces.len();  // 这里就是shadowing,新变量隐藏了旧的
    println!("len: {}",spaces); // len: 5
    // 隐藏使用我们不必使用不同名字,如:spaces_str; spaces_num来表示不同的意思,

    let mut spaces_mut = "    ";
    // spaces_mut  =  spaces_mut.len();  // mut不能跨类型
    spaces_mut = "不能改变类型";
    println!("mut_len: {}",spaces_mut);  
    // mut 使用我们不用再次let,来改变变量的值,但是有个问题不能跨类型
}

  

在Rust中的数据类型

  在Rust中可以分为两类类型:标量和复合,我们之前做猜数字的游戏中使用到了:let  guess: u32 = "42".parse().expect("Not a number"), 需要指定需要转换成的类型,由于Rust是静态语言,在编译前需要知道每个变量的类型。

1、标量类型:

  标量(scalar)类型代表一个单独的值,Rust有四种基本的标量类型: 整型、浮点型、布尔和字符类型。

  复合类型(compound types)可以将多个值组合成一个类型,Rust有两个原生的复合类型:元祖和数组。

fn main() {
    let  tup:(i32, f64, u8) = (500,6.0,1); // 每个元素都指定类型
    println!("The tup: {:?}",tup);
    // let tup1: (i32;4) = (1,2,3,4);  // ERR:同一类型,多个数量,不能这样
    // println!("The tup1:{}",tup1);
    let tup2 = (2,3,4);
    let (x,y,_) = tup2;  // 必须解构完
    println!("The x,y: {} {}",x,y);

    println!("The z: {}",tup2.2); // 默认是0开始
}

 

2、复合类型

  多个值的方式是数组,与元祖不同的是,数组中的每个元素的类型必须相同。Rust的数组和其他语言不同,它是固定长度的,一旦声明,长度是不能增加或减少的。当你想要在栈(stack)而不是在堆(heap)上为数据分配空间,或者要确保总是有固定数量的元素时,数组是非常有用的。但是数组并不如vector类型灵活。vector类型是标准库提供的一个允许增长和缩小长度的类似的数组的集合类型。当不确定是应该使用数组还是vector的时候,应该使用vector。

fn main() {
    // 数组定义
    let a = [1,2,3,4];  // 同一种类型
    // 声明数组
    let b:[i32;3] = [5,6,7];
    println!("a: {:?}, b: {:?}",a,b);

    // 数组适用场景,比如月份/星期,它是不会变动的
    let c = ["January","February","March","April"];
    
    let d = [3;5];  // 5个3
    println!("d: {:?} 第三个{}",d,d[2]);
}

  当发生越界操作时,会发生一个“RUST_BAXKTACE=1"的报错,发生panic。

  

  

 

  

 

posted @ 2020-06-09 10:06  独角兕大王  阅读(398)  评论(0编辑  收藏  举报