zoukankan      html  css  js  c++  java
  • Rust 入门 (三)_上

    这部分我们学习 rust 语言的 变量、数据类型、函数、注释、流程控制 这五个方面的内容。本文我们介绍前两个内容,下一篇文章介绍后三个内容。

    变量

    默认情况下,rust 语言中声明的变量是不可变的,比如如下代码:

    fn main() {
        let x = 5;
        println!("x 的值是: {}", x);
        x = 6;
        println!("x 的值是: {}", x);
    }
    

    我们先来跑一下这段代码:

    cargo run                                                                                                                                                                                         
       Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
    error[E0384]: cannot assign twice to immutable variable `x`
     --> src/main.rs:4:5
      |
    2 |     let x = 5;
      |         -
      |         |
      |         first assignment to `x`
      |         help: make this binding mutable: `mut x`
    3 |     println!("x 的值是: {}", x);
    4 |     x = 6;
      |     ^^^^^ cannot assign twice to immutable variable
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0384`.
    
    

    通过运行结果,我们发现这段代码有问题的,然后我们从报错信息中抓取关键信息: cannot assign twice to immutable variable,它的意思是 不可变变量不能进行二次赋值。但是有些时候,我们也需要修改变量的值,应该怎么办呢,在变量名的前面,let 关键字的后面添加一个关键字 mut 就行了,我们来试试:

    fn main() {
        let mut x = 5;
        println!("x 的值是: {}", x);
        x = 6;
        println!("x 的值是: {}", x);
    }
    

    运行一下代码:

    cargo run                                                                                                                                                                                      
       Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
        Finished dev [unoptimized + debuginfo] target(s) in 3.53s
         Running `target/debug/hello_cargo`
    x 的值是: 5
    x 的值是: 6
    

    这种不可变变量的设计有着很多安全方面的考虑,这里不再赘述。谈到这里,很容易联想到编程语言的另一个概念——常量,那二者有什么区别呢?
    1.常量不能使用 mut 关键字修饰,常量在任何情况下都是不可变的(变量是在默认情况下不可变)。
    2.常量使用 const 关键字来声明,而变量使用 let 关键字来声明。
    3.常量需要在常量名后面紧跟冒号和类型,例如 const MAX_POINTS: u32 = 100_000;,而变量可以省略冒号和类型的修饰。
    4.常量的作用域是任何作用域,包括全局作用域。
    5.常量只能使用常量表达式赋值,而不能使用函数结果或者其它运行时产生的值。

    注:这是说明一下,常量通常使用大写字母和下划线 _ 来命名。


    我们再来说一个变量的特性——覆盖。在上一篇写猜数字游戏的文章中,我们做数字类型转换的时候,新类型的名字使用了旧类型的名字,这种情况就是覆盖。先来个实例:
    fn main() {
        let x = 5;
        println!("x 的值是: {}", x);
        let x = 6;
        println!("x 的值是: {}", x);
    }
    

    我们来看运行结果:

    cargo run                                                                                                                                                                                          
       Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
        Finished dev [unoptimized + debuginfo] target(s) in 0.36s
         Running `target/debug/hello_cargo`
    x 的值是: 5
    x 的值是: 6
    

    通过结果可以发现,第二个使用 let 关键字修饰的不可变变量 x 把第一个 x 覆盖了,也就是说把 x 的值从 5 改成了 6。那这和 mut 有什么区别呢?
    1.覆盖的第二个变量需要使用 let 关键字修饰,如果没有 let 关键字,则会报错。
    2.覆盖的第二个变量不仅可以改变值,还可以修改变量的类型;而 mut 不可以改变类型。

    这里举两个例子来说明第二个区别:

    fn main() {
        let space = "abc";
        println!("space 代表的是:{}", space);
        let space = space.len();
        println!("space 代表的是:{}", space);
    }
    

    先来运行第一个例子:

     cargo run                                                                                                                                                                                          
       Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
        Finished dev [unoptimized + debuginfo] target(s) in 0.22s
         Running `target/debug/hello_cargo`
    space 代表的是:abc
    space 代表的是:3
    

    然后看第二个例子:

    fn main() {
        let mut space = "abc";
        println!("space 代表的是:{}", space);
        space = space.len();
        println!("space 代表的是:{}", space);
    }
    

    跑一下第二个例子:

    cargo run                                                                                                                                                                                         
       Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
    error[E0308]: mismatched types
     --> src/main.rs:4:13
      |
    4 |     space = space.len();
      |             ^^^^^^^^^^^ expected &str, found usize
      |
      = note: expected type `&str`
                 found type `usize`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0308`.
    error: could not compile `hello_cargo`.
    
    To learn more, run the command again with --verbose.
    
    

    可以轻易看到二者的区别,好了,接下来我们看 rust 的基本类型。

    数据类型

    rust 的数据类型就是在编译期间告诉 rust 的编译器如何处理这些数据。在这里,我们会了解到两种数据类型:基本数据类型和组合数据类型。

    基本数据类型

    基本数据类型也就是简单值,rust 主要包含了 4 种基本数据类型,分别是整型、浮点型、布尔型和字符型。你可能在其他语言中见过这些类型,现在,我们来看一下它们在 rust 语言中是怎么样的。

    整型

    整型是不包含小数的数字类型。整型包含了两种类型:i 打头的有符号整型和 u 打头的无符号整型。我们使用一个表格来描述 rust 的整型:

    占用空间 有符号整型 无符号整型
    8-bit i8 u8
    16-bit i16 u16
    32-bit i32 u32
    64-bit i64 u64
    128-bit i128 u128
    格式 i+长度 u+长度

    整型在使用过程中默认类型是 i32。

    浮点型

    浮点型包含了两种类型:单精度浮点型 f32,双精度浮点型 f64。浮点型在使用过程中默认类型是 f64。

    数据操作

    rust 支持的基本数据操作有:加 +,减 -,乘 *,除 /,取模 %。

    布尔型

    布尔型通常有两个值:true和false。它占用 1 个字节,使用 bool 关键字来声明。

    字符型

    rust 的字符类型占用 4 个字节,它的值是使用单引号 ' 引起来的。

    组合数据类型

    组合数据类型是把多个值组合成一个类型。在 rust 中,组合数据类型有两种:元组和数组。

    元组

    元组是把多个基本类型组合成一个组合类型。它有一个确定的长度,一旦确定就不能再次加减元素了。我们先来看一个元组的实例:

    fn main() {
        let tup: (i32, f64, u8) = (500, 6.4, 1);
        println!("第0个值:{}, 第1个值:{}, 第2个值:{}", tup.0, tup.1, tup.2);
    
        let (x, y, z) = tup;
        println!("x的值:{}, y的值:{}, z的值:{}", x, y, z);
    }
    

    它运行的结果是:

    cargo run                                                                                                                                                                                          
       Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
        Finished dev [unoptimized + debuginfo] target(s) in 0.23s
         Running `target/debug/hello_cargo`
    第0个值:500, 第1个值:6.4, 第2个值:1
    x的值:500, y的值:6.4, z的值:1
    
    

    元组的取值有两种方式,一种是把元组解构成多个变量,另一种就是使用 . 的方式,顺序是从 0 开始。

    数组

    数组和元组不一样的地方是:数组只能使用相同的数据类型。数组和元组相同的地方是:长度一旦确定就不能加减元素了。如果想改变数组的长度,可以使用 vector 类型,后续文章会介绍 vector 类型的情况。而且数组还有一个特性,它会把数据分配到栈内存,而不是堆内存。下面举几个常用的数组的例子:

    fn main() {
        // 定义一个简单的数组
        let a = [1, 2, 3, 4, 5];
    
        // 定义一年 12 个月,而且不需要增减月份,那么可以直接定义包含 12 个月份的数组
        let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    
        // 定义包含 5 个元素的 i32 类型的数组
        let a: [i32; 5] = [1, 2, 3, 4, 5];
    
        // 数组的值是 5 个 3
        let a = [3; 5];
    
        // 取值
        println!("a[3]的值是:{}", a[3]);
        println!("a[9]的值是:{}", a[9]);  // 编译时这里会报错:error: index out of bounds: the len is 5 but the index is 9
    }
    

    数组的取值方式是以中括号 [0] 的方式,顺序是从 0 开始。如果取值越界,rust 会在编译期告诉你,这就是 rust 安全原则的第一个例子。


    这一节未完,待续~~~

    欢迎阅读单鹏飞的学习笔记

  • 相关阅读:
    如何使用sqlalchemy根据数据库里面的表反推出模型,然后进行查询
    5.多项式回归与模型泛化
    numpy中与高等数学有关的函数
    4.pca与梯度上升法
    你真的了解内置函数iter吗?
    peewee:精致小巧的orm,sqlalchemy的一个很好的替代品
    事件对象
    JS的事件流的概念(重点)
    jQuery的位置信息
    小米导航案例
  • 原文地址:https://www.cnblogs.com/shanpengfei/p/11953188.html
Copyright © 2011-2022 走看看