rust 入门

1.数据类型


struct Point {
    x : i32,
    y : u32,
    msg: String,
}

fn simple_func(){
    let p = Point{x:25, y: 25, msg: String::from("point") };
    let p1 = p;
    println!("{} {} {}", p1.x, p1.y, p1.msg);
}

fn main() {
    simple_func();
}
1.1 整数型
  • 整数型有 isize 与 usize 两种类型,用来衡量数据大小。如上图 i32为 32位的 isize 类型。
  • 整数型定义
位长isizeusize
8biti8u8
16biti16u16
32biti32u32
64biti64u64
128biti128u128
1.2 浮点类型
  • 浮点类型有 32精度 和 64精度。定义分别为x:f64, y: f32
  • 默认是64精度位 let x = 100.00; // 64精度位
1.3 字符型
  • 字符型关键字用 char 标识

不讲太多,不好吸收(还有布尔型 与 复合类型)

2 所有权

2.1 所有权转移
fn simple_func(){
    let p = Point{x:25, y: 25, msg: String::from("point") };
    let p1 = p;
    /**
     value borrowed here after move
     p 所有权被移除
    */
    // println!("{} {} {}", p.x, p.y, p.msg);
    /**
     所有权属于 p1
    */
    println!("{} {} {}", p1.x, p1.y, p1.msg);
}
  • Point 这数据所有权属于 p 对象
  • p1 = p 之后, Point 的所有权转移到 p1
  • Point 这个数据的所有权只能属于一个变量
  • 一个数据(java 所说的对象)所有权只属于一个变量(指针)
  • 由于所有权的存在:一块内存只有一个所有权,当所有权变量(pp1)不存在了,Pont 的内存就会被编译器回收。
2.2 引用
2.2.1 只读引用
  • 只读不能修改,避免多线程对于单个对象修改造成的线程不安全问题
let  p = Point{x:25, y: 25, msg: String::from("point") }; // read-only
p.x = 35; // 编译不通过
println!("{} {} {}", p.x, p.y, p.msg);
  • mut 关键字声明可变
let mut  p = Point{x:25, y: 25, msg: String::from("point") };
p.x = 35;
println!("{} {} {}", p.x, p.y, p.msg);
```#### 2.3 借用 borrowing
##### 2.3.1 所有权回收
```go
fn simple_borrow(){
     let p1 = Point{x : 25, y : 25};
     fn1(p1);// 所有权转移 p 转移-> 形参p
     print!("{} {}",p1.x, p1.y)
}
fn fn1(p: Point){} // p 所有权转移,函数声明周期结束了,p 指向的数据(内存)被回收
  • p1 对象会在函数结束时候被回收。编译不通过:move occurs because p1 has type Point, which does not implement the Copy trait
  • 由此出现 borrowing 的概念。
2.3.2 所有权借用
  • 函数 形参 借用(borrowing)传参 指向对象的 所有权
  • 使用 & 借用类型
  • 不要与 go 语言与 c++ 的关键字混起来记
fn simple_borrow(){
    let p1 = Point{x : 25, y : 25};
    fn1(&p1); //& 对象(内存或数据)所有权暂时借用给函数内的的形式参数,不要跟go或者c的混着记
    print!("{} {}",p1.x, p1.y)
}
fn fn1(_p: &Point){}// 函数结束后,_p 指向数据的所有权还给 p1
2.3.3 可变借用 borrowing mutable
  • 定义的对象是可变的对象 mut 与 可变的借用对象 &mut
fn simple_borrow(){
    let mut p1 = Point{x : 25, y : 25};
    fn1(&mut p1); //& 对象(内存或数据)所有权暂时借用给函数内的的形式参数,不要跟go或者c的混着记
    print!("{} {}",p1.x, p1.y)
}

fn fn1(_p: &mut Point){
    _p.x = 35
}// 函数结束后,_p 指向数据的所有权还给 p1

数据竞争 的产生条件

  • 两个或更多指针同时访问同一数据。
  • 至少有一个指针被用来写入数据。
  • 没有同步数据访问的机制。

为了避免 数据竞争mut 可变引用使用有如下编译规则

  • 对一个数据的引用的 作用域 声明,在同一个作用域内,不能 同时 拥有两个或以上可变借用(不能同时有两个 mut 引用修改数据导致数据不一致)
  • 同一作用域内,不能 同时 存在 不可变引用借用 与 可变引用借用。

错误

fn main() {
    let mut s = String::from("hello");
    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    let r4 = &mut s; // 有问题
    println!("{} and {} and {}", r1, r2, r3);// 问题出现在这个调用,即使用了 s 的不可变借用 与 可变借用(r1,r2,)
}

正确

fn main() {
    let mut s = String::from("hello");
    let r1 = &s; // 没问题
    let r2 = &s; // 没问题
    println!("{} and {}", r1, r2);
    // 此位置之后 r1 和 r2 不再使用
    let r3 = &s; // 没问题
    println!("{}", r3);
}
2.3.4 悬垂指针
  • 在具有指针的语言中,当指针指向的内存被释放以后而错误产生一个悬垂指针。(可以理解为 java 内的空指针)
  • 在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域。(内存会迟于引用被释放)

3 智能指针

3.1 Box指针 保证分配在堆上
  • 数据所有权一般在函数的生命周期内,数据一般分配在方法栈内
  • 数据写在堆内存上
  • 引用独占所有权,该数据只能有一个应用指向
方法内引用
堆内存
3.2 Rc 引用计数,单线程,只读
  • 引用计数指针,该指针保存着这份内存数据的引用计数
  • 一份数据所有权可以给多个引用指向,通过克隆的形式。该形式与java的克隆概念不同,rust的克隆是多个引用指向同一个数据
  • 当所有应用不再指向这份数据的时候,这份数据被回收
引用1
堆内存
引用2
引用3
fn rc_new_thread(){
    let p = Rc::new(Point{x:25, y:25});
    let p1 = Rc::clone(&p); // 克隆一份
    let p2 = Rc::clone(&p); // 克隆一份
    println!("p: {} {}", (*p).x , (*p).y);
    println!("p1:{} {}", (*p1).x , (*p1).y);
    println!("p2:{} {}", (*p2).x , (*p2).y);
}
3.3 Arc 多线程引用计数,只读
  • 原子性引用计数,该数据可以通过 move 转移所有权到多个线程中。
fn thread_Arc_two() {
    let p = Arc::new(Point{x:30, y:30});
    let p1 = Arc::clone(&p);
    let p2 = Arc::clone(&p);
    let h1 = thread::spawn(move ||{ // move 对象所有权转移
        println!("{}", p1.x);
        thread::sleep(Duration::from_millis(100));
    });
    let h2 = thread::spawn(move ||{ // move 对象所有权转移
        println!("{}", p2.x);
        thread::sleep(Duration::from_millis(100));
    });
    h1.join();
    h2.join();
}
3.4 Mutex 互斥指针
  • 智能指针指向特定的数据,该指针内有一把锁,只允许一个引用修改数据
  • 将该数据传递到多线程去修改,需要通过 Arc 指针封装,可以使多个引用指向该 Mutex 指针。这样多线程也可以获取到 Mutex 指针去修改这份数据
fn thread_two_write(){
    let mut p_mutex = Arc::new(Mutex::new(Point{x:0, y:0}));
    let p1 = Arc::clone(&p_mutex);
    let p2 = Arc::clone(&p_mutex);
    thread::spawn(move ||{
        let mut p = p1.lock().unwrap();
        p.x += 1;
        println!("{} {}", p.x, p.y)
    }).join();
    thread::spawn(move ||{
        let mut p = p2.lock().unwrap();
        p.x += 1;
        println!("{} {}", p.x, p.y)
    }).join();
}
未完待续…
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霸道产品爱上我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值