Rust 学习笔记 - 原生类型

作者: 不告诉你_ | 来源:发表于2017-03-21 20:58 被阅读127次

    布尔型:

    布尔类型(bool)只有两个值:truefalse

    let x = true;
    let y: bool = false;
    

    布尔型通常用在 if 语句中, 也可以用在 match 语句中:

    fn main() {
        let praise_the_borrow_checher = true;
    
        if praise_the_borrow_checher {
            println!("oh, yeah!");
        } else {
            println!("what?!!");
        }
    
        match praise_the_borrow_checher {
            true => println!("keep praising!"),
            false => println!("you should praise!"),
        }
    }
    

    还可以将字符串 “true” 和 “false” 转换为 bool:

    use std::str::FromStr;
    
    fn main() {
        assert_eq!(FromStr::from_str("true"), Ok(true));
        assert_eq!(FromStr::from_str("false"), Ok(false));
        assert!(<bool as FromStr>::from_str("not even a boolean").is_err());
    }
    

    也可以这样:

        assert_eq!("true".parse(), Ok(true));
        assert_eq!("false".parse(), Ok(false));
        assert!("not even a boolean".parse::<bool>().is_err());
    

    可以在标准库文档查看更多 bool 的说明。

    char

    char 类型代表一个单独的 Unicode 字符的值。可以使用单引号 ' 创建 char:

    let x = 'x';
    let two_hearts = '💕';
    

    与其他语言不同的是,Rust 的 char 并不是1个字节,而是4个。因而我们可以将各种奇怪的字符随心所欲的赋值给一个 char 类型。

    可以在标准库文档查看更多 char 的说明。

    数字类型

    数字类型分为有符号整数(i8, i16, i32, i64, isize)、无符号整数(u8, u16, u32, u64, usize)和浮点数(f32, f64)。其中,isizeusize 也称为可变大小类型或自适应类型,其大小依赖底层机器指针大小,意思就是:32位电脑上就是32位,64位电脑上就是64位。

    如果一个数字,没有推断它类型的条件,将采用默认类型:

    let x = 123; //i32
    let y = 1.23; //f64;
    let c = -456; //i32;
    

    需要说明的是,这里的“没有推断它类型的条件” 中的 “条件”。比如:

    fn main() {
        let a = 18446744073709551615;
        println!("{:?}", a);
    }
    

    Rust 不会根据赋给 a 的值推断 a 的类型,a 仍然是i32类型,把一个大于32位的值赋给i32类型,会警告越界:

       Compiling hello_world v0.1.0 (yourpath/hello_world)
    warning: literal out of range for i32, #[warn(overflowing_literals)] on by default
     --> main.rs:2:13
      |
    2 |     let a = 18446744073709551615;
      |             ^^^^^^^^^^^^^^^^^^^^
    
        Finished debug [unoptimized + debuginfo] target(s) in 0.47 secs
         Running `yourpath\hello_world\target\debug\hello_world.exe`
    -1
    

    即使能编译成功,也将变为-1。如果给定一个接收者,比如一个函数:

    fn main() {
        let a = 18446744073709551615;
        print(a);
    }
    
    fn print(n: u64) {
        println!("{:?}", n);
    }
    

    这样,Rust 就能根据 print 函数所接受的 u64 类型推断出 a 的类型为 u64

    如果显示的标注类型,有两种方式:

    let x: i32 = 123;
    let y: f64 = 1.23;
    

    或者通过后缀的方式:

    let x = 123i32;
    let y = 1.23f64;
    

    以上两种方式是等价的。

    为了可读性,可以在数字之间加上下划线 _

    let x = 1_000i32; // 1000
    let y = 1_234_567; // 1234567
    let z = 0.000_001; // 0.000001
    

    如果你想的话,这样都可以:

    let x = 1000_i32;
    let y = 1.23_f64;
    

    还可以加上前缀 0x0o0b 分别表示十六进制数、八进制数、二进制数:

    let a = 0b11111111; //255
    let b = 0o77777777; //16777215
    let c = 0xFFFFFF;  //16777215
    

    可以标准库文档中查看每种类型的详细说明:i8i16i32i64u8u16u32u64isizeusizef32f64

    数组(array)

    数组是一组包含相同数据类型 T 的组合,并存储在连续的内存区中。数组使用中括号 [] 来创建,其大小在编译期间就已确定,数组的类型被标记为 [T; size],表示一个拥有 T 类型,size 个元素的数组。数组的大小是固定的,但其中的元素可以被更改。

    fn main() {
        let mut array: [i32; 3] = [0; 3]; // 0, 0, 0
    
        array[1] = 1;
        array[2] = 2;
    
        println!("{:?}", array); // 0, 1, 2
    }
    

    可以用 array.len() 获取数组的元素数量:

    fn main() {
        let array = [0; 20];
        println!("{:?}", array.len()); // 20
    }
    

    可以使用下标访问特定元素:

    fn main() {
        let names = ["Graydon", "Brian", "Niko"]; // names: [&str, 3]
        println!("The second name is: {}", names[1]); // Brian
    }
    

    跟大部分编程语言一样,下标从0开始,所以第一个元素是 names[0], 第二个是 names[1。如果你尝试使用一个不存在于数组中的下标,将会得到一个错误,数组访问会在运行时进行边界检查。

    可以在标准库文档中查看更多 array 的详细说明。

    切片(slice)

    切片是一个数组的引用(或者“视图”)。它有利于安全,有效的访问数组的一部分而不用进行拷贝。比如,你可能只想要引用读入到内存文件中的一行。原理上,切片并不是直接创建的,而是引用一个已经存在的变量。片段有预定义长度,可以是可变的也可以是不可变的,但是其范围不能超过数组的大小。

    在底层,切片代表一个指向数据开始的指针和一个长度。

    一个切片的表达式可以为 [T]&mut [T]

    let array = [1, 2, 3, 4, 5, 6];
    let slice_complete = &array[..]; // 获取全部元素
    let slice_middle = &array[1..4]; // 获取中间元素,取得的 Slice 为 [2, 3, 4]。切片遵循左闭右开原则。
    let slice_right = &array[1..]; // [2, 3, 4, 5, 6]
    let slice_left = &array[..3]; // [1, 2, 3]
    

    可以在标准库文档中查看更多切片的说明。

    元组(tuples)

    元组是固定大小的有序列表,使用括号 () 来构成,每个元组的值都是 (T1, T2, ...)类型标记的形式,其中 T1, T2 是每个元素的类型。 如下:

    let x = (1, "hello", "world");
    

    这是一个长度为3的元组,下面是同样的元组,不过注明了数据类型:

    let x: (i32, &str, &str) = (1, "hello", "world");
    

    如你所见,元组的类型跟元组看起来很像,只不过类型取代值的位置。

    可以把一个元组赋值给另一个,如果他们包含相同的类型和数量。当元组有相同的长度时他们后相同的数量。

    let mut x = (1, 2); // x: (i32, i32)
    let y = (2, 3); // y: (i32, i32)
    
    x = y;
    

    可以通过一个let “解构”访问元组中的字段:

    let (x, y, z) = (1, 2, 3);
    
    println!("x is {}", x);
    

    我们可以在 let 左侧写一个模式,如果能匹配右侧的话,可以一次写多个绑定。这种情况下,let “解构” 或 “拆开” 了元组,并分成了三个绑定。这个模式时很强大的。

    可以用一个逗号来消除一个单元素元组和一个括号中的值的歧义:

    (0, );
    (0);
    

    可以用索引访问一个元组中的字段:

    let tuple = (1, 2, 3);
    
    let x = tuple.0; // 1
    let y = tuple.1; // 2
    let x = tuple.2; // 3
    

    就像数组索引,元组索引从 0 开始,不过也不像数组索引,它使用 ., 而不是 []

    函数可以利用元组来放回多个值,因为元组可以拥有任意数量、不同类型的值。

    fn mian() {
        let (p2, p3) = pow_2_3(456);
        println!("pow 2 of 456 is {}.", p2);
        println!("pow 3 of 456 is {}.", p3);
    }
    
    fn pow_2_3(n: i32) -> (i32, i32) {
        (n * n, n * n * n)
    }
    

    可以在标准库文档中查看更多元组的说明。

    str

    Rust 的 str 类型是最原始的字符串类型。作为一个不定长类型,它本身并不是非常有用,不过当它在引用后就是有用的了,例如 &str。事实上,Rust 中所有用 "" 包裹起来的都可以称为 &str,但是这个类型单独使用的情况很少。将在后续章节详细介绍字符串类型。

    可以在标准库文档中查看更多 str 的说明。

    函数

    函数也有一个类型,他们看起来像这样:

    fn foo(x: i32) -> i32 { x }
    
    let x: fn(i32) -> i32 = foo;
    

    在这个例子中,x 是一个“函数指针”,指向一个获取一个 i32 参数并返回一个 i32 值的函数。

    相关文章

      网友评论

        本文标题:Rust 学习笔记 - 原生类型

        本文链接:https://www.haomeiwen.com/subject/altnnttx.html