Posts for: #Learning

Rust:Generic and Traits

泛型

Rust 泛型会在编译时根据参数将泛型单态化(Monomorphization ),因此,Rust 泛型在运行时是没有任何损耗的。

泛型在函数定义

fn largest<T: std::cmp::PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let number_list = vec![34, 50, 43, 15];
    println!("the largest number is {}", largest(&number_list));

    let char_list = vec!['y', 'm', 'c', 'd'];
    println!("the largest char is {}", largest(&char_list));
}

泛型在结构体定义

struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let p = Point{x: 5, y: 3};
    println!("x is {}, y is {}", p.x, p.y);

    let p = Point{x: 5.0, y: 3.0};
    println!("x is {}, y is {}", p.x, p.y)
}

需要注意,这里表示结构体内x和y是同一种类型,如果需要x和y类型不同,需要定义两个泛型参数。

Rust:Ownership

所有权(Ownership)是Rust中最独特的特性之一。正是因为所有权,Rust才能够在不需要GC的情况下保证内存安全。

我们常用的语言中,内存管理一般分为两种:

  • 自管理,谁分配的谁负责回收,如果没有回收,就会导致内存泄漏。如C、C++。
  • 由统一的垃圾回收器管理,GC负责追踪和管理已分配内存,如果内存不再被使用,则由GC进行回收。

Rust选择了第三种,内存会在拥有它的变量离开作用域时回收。因此,理解Rust的内存管理,就需要理解Rust中的所有权、借用规则、生命周期等概念。Rust会在编译过程中校验变量是否符合借用规则,从而保证运行时的内存安全,而且没有GC的额外开销。

在C++中,这种模式也被称作Resource Acquisition Is Initialization (RAII)

所有权基本规则

所有权有三条基本规则:

  • Rust中每个值都有一个对应的变量称之为所有者(owner);
  • 同一时刻,一个值只能存在一个所有者;
  • 当所有者离开作用域时,其拥有的值会被丢弃。

copy和move

因为同一时刻,一个值只能存在一个所有者,对于所有权的转让,Rust根据对象类型分为两种。

一种是Copy。即将值做拷贝,拷贝后,原变量拥有原值的所有权,新变量拥有新值的所有权,没有所有权的转移,两者可以同时使用。

let x = 5;
let y = x;
println!("x is {}, y is {}", x, y); // valid

支持Copy操作常见的类型通常是只存储在栈上的数据类型,如:

  • 所有的integer类型,如u32;
  • bool值;
  • char值;
  • 所有的float类型,如f64;
  • 元组,如果其包含的类型也都是支持Copy的。

这些类型都实现了Copy特型。如果一种类型实现了Copy特型,在分配新变量后,原变量仍是可用的。

另外一种是Move。对于类似String这种在栈上存储了元数据,实际数据存储在堆上的数据类型来说,将原变量赋给新变量实际上是将堆上数据的所有权转移给新变量,原变量在赋值后不再使用。

let s1 = String::from("hello!!!");
let s2 = s1;
println!("s2 is {}, s1 is {}", s2, s1); // invalid, s1 is no longer valid any more.

image-20210623093004432