Rust 第一期学习记录

Rust 一门赋予每个人构建可靠且高效软件能力的语言。具有高性能、可靠性、和生产力三大特点。

Rust 第一期学习记录_第1张图片
image.png

接下来就从安装,开发环境搭建、基础概念和语法了解三个部分介绍第一周学习Rust的情况。默认为Mac环境

0、安装Rust

优先建议使用rustup工具进行安装操作

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

另外如果本地已经安装了较低的版本,则可以通过rustup update进行版本升级操作,经过一阵子的等待之后,rust安装文案提示成功即可,还需要配置环境变量

可以在用户当前的根目录下的.bash_profile文件末尾添加如下配置

# rust
export PATH=$PATH:$HOME/.cargo/bin

最后进行source .bash_profile 刷新即可。通过如下操作检验是否安装成功,参数一定得是大写的V

➜  ~ cargo -V
cargo 1.51.0 (43b129a20 2021-03-16)
➜  ~ rustc -V
rustc 1.51.0 (2fd73fabe 2021-03-23)

cargo Rust构建工具和包管理器,在安装Rust的时候,会自动安装Cargo

  • cargo build 构建项目
  • cargo run 运行项目
  • cargo test 测试项目
  • cargo doc 构建项目文档
  • cargo publish 将当前的库发布到cartes.io 上

至此整个的运行环境就已经搭建完毕

1、开发环境搭建

VS Code作为开发环境,安装好Rust的相关插件,插件rls,

  • Rust代码支持,rls
Rust 第一期学习记录_第2张图片
image.png
  • Rust包版本管理工具,crates
Rust 第一期学习记录_第3张图片
image.png
Rust 第一期学习记录_第4张图片
image.png
  • TOML文件高亮支持


    Rust 第一期学习记录_第5张图片
    image.png

在终端环境输入cargo new rust-learn就会自动的创建rust-learn项目,其中的src文件包含了入口文件main.rs

Rust 第一期学习记录_第6张图片
image.png

运行也就可以直接在终端输入cargo run即可,出现的warning只是警告信息,并不会影响程序的执行,而Error则会停止服务的运行

Rust 第一期学习记录_第7张图片
image.png

至此,已经可以开始进行demo的编写,语法的学习以及正常的代码开发工作了。

2、基础知识学习

  • 官方Rust学习文档
  • Rust学习资料在线网站
  • Rust教程

Rust的突击学习一周,感觉Rust是个大杂烩,包含了多种语言的相关特点,例如:

  • 变量声明的时候采用了JS的规则,可是其又是一个强类型的语言,Rust可以手动自定义类型也可以根据具体数据推测其数据类型;
  • 默认是不可变的,如果需要变成可变的则需要手动添加mut可变关键字,这个和scala类似;
  • 内存管理则吸收了C和Java的特点,C里面需要手动申请和释放内存,而Java则是由JVM统一管理,Rust则是自动申请内存,而在当前的作用域完成之后,自动的添加相关内存释放的操作;
  • 有类似scala的trait特性,其初步理解和接口比较接近,默认返回一个数据的时候可以不用写return关键字
  • 有类似C语言的&指针的概念,为数据的所有权做好足够的约束

说了这么多,接下来就来学习一个Rust吧~

数据类型

Rust是一门强类型的语言,其类型分为整型,浮点型,布尔类型,字符类型 几种类型,在使用的时候都应该带上具体是8位还是16位的相关说明,而不是和java一样,完全由JVM屏蔽了其对象大小的细节情况,从另一个角度来看,也可以节省内存吧。

  • 整型
位长度 有符号 无符号 表达形式
8-bit i8 u8 0o77,0o16
16-bit i16 u16 0xff,0x12
32-bit i32 u32 -
64-bit i64 u64 -
128-bit i128 u128 -
arch isize usize -
  • 浮点型

f32f64两种类型

  • bool布尔类型

truefalse两种

  • 字符型

char字符类型,一般是4个字节,因为是4个字节,那么就可以支持中文、日文、emoji表情等数据,使用UTF-8作为编码格式,注意使用GBK之后导致的乱码情况,使用单引号括起来

不可变,可变,重影,常量

代码Demo如下

fn test01() {
    let a = "Hello";
    // 1、a = "zhangsan"; 不可变对象
    // 会提示错误 「cannot assign twice to immutable variable」
    let a = "lisi";
    // 2、重影
    println!("a:{}", a);

    let mut b = "Hello";
    b = "zhangsan";
    // 3、可变对象
    println!("b:{}", b);
    
    const Count:i32 = 32;
    // 4、常量
    println!("count:{}", Count);
}

运行结果:

    Finished dev [unoptimized + debuginfo] target(s) in 1.22s
     Running `target/debug/rust-learn`
a:lisi
b:zhangsan

使用let关键字进行声明变量,而且默认是不可变对象,如果再对其进行赋值操作,则会出现错误「cannot assign twice to immutable variable」,这点和对Java的认识是不一样的,一旦固定下来了,就是不可变的。可以使用let mut关键字设置可变对象重影Shadowing则是给当前赋值对象重新指向一个数据

总结&理解
默认不可变可能是Rust从高并发安全的角度设计的,尽量减少对数据的改值操作
重影shadowing则是一个新的概念,此外并没有接触,还是应该从内存管理的角度理解吧,如代码中2的操作之后,之前的Hello对象,就会被系统自动的remove
常量必须指定数据类型,而且应该是具体的数据表达式,而不是什么方法之类的,此外也不可用于重影操作
Rust对内存、安全的要求有点严苛

String、&str和所有权

先看看如下代码

fn test02() {

    fn cp(content: String) {
        println!("content:{}", content);
    }

    let a = "Hello World";   // 1
    cp(a);
    println!("a:{}", a);
}

代码很简单,大致也能知道只需要传入一个String的参数数据进行打印操作,然后把数据本身再打印一次,如果正常的话,则会输出两遍结果。但是意外的是,这个代码出现了2个错误

  • 错误1 cp方法出现错误 expected struct String, found &str

报错意思很明显,希望传入的String类型,但是实际传入的则是&str,这就引出来了一个情况,1处的代码生命的对象实际上是&str类型,而不是期望的String

  • String是一个可变的、堆上分配的UTF-8的字节缓冲区,存在len()和capacity()方法
  • str是一个不可变的固定长度的字符串,只有一个len()方法
  • &不能仅仅理解成指针,实际上是租借borrowed的意思
    Rust 第一期学习记录_第8张图片
    image.png

那么怎么解决问题呢,把方法定义和传入的参数定义统一即可,都改成String,或者&str,甚至&String等

&str ==> String的几种方案

let a = "hello";
let b1 = a.to_string();
let b2 = String::from(a);
let b3 = a.to_owned();

String ==> &str的几种方案

let a = String::from("hello");

let b1 = &a;
let b2 = a.as_str();
  • 错误2:最后的一行出现错误 value borrowed here after move

意思很清楚,数值被使用的时候已经被remove掉了,就无法使用,为什么呢?

主要原因是因为传入到cp方法的参数是对象a本身,a的作用域已经被移动到方法内部了,随着作用域的改变,在方法外的打印操作就属于作用域外的调用执行,所以就被理解成remove掉了,那么自然就会出现失败的情况。再看一个下面的代码,加强对所有权的理解

fn main() {
    let s = String::from("hello");
    // s 被声明有效

    takes_ownership(s);
    // s 的值被当作参数传入函数
    // 所以可以当作 s 已经被移动,从这里开始已经无效

    let x = 5;
    // x 被声明有效

    makes_copy(x);
    // x 的值被当作参数传入函数
    // 但 x 是基本类型,依然有效
    // 在这里依然可以使用 x 却不能使用 s

} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放


fn takes_ownership(some_string: String) {
    // 一个 String 参数 some_string 传入,有效
    println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放

fn makes_copy(some_integer: i32) {
    // 一个 i32 参数 some_integer 传入,有效
    println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放
fn main() {
    let s1 = gives_ownership();
    // gives_ownership 移动它的返回值到 s1

    let s2 = String::from("hello");
    // s2 被声明有效

    let s3 = takes_and_gives_back(s2);
    // s2 被当作参数移动, s3 获得返回值所有权
} // s3 无效被释放, s2 被移动, s1 无效被释放.

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    // some_string 被声明有效

    return some_string;
    // some_string 被当作返回值移动出函数
}

fn takes_and_gives_back(a_string: String) -> String { 
    // a_string 被声明有效

    a_string  // a_string 被当作返回值移出函数
}

最后自己尝试着用各自方法解决一下demo中出现的错误

总结&理解
String和str是完全不同的两种数据结构,默认定义一个字符串是str的类型
在使用方法的时候,写的参数一定需要注意到,是否有使用引用,是否被提前移除等情况

暂时就先总结这么多,后面的继续学习和更新

你可能感兴趣的:(Rust 第一期学习记录)