Rust程序设计第二版-把书读薄之一些细节点

26 次浏览
2024年07月26日创建

泛型跟在方法名后

fn say_hello(out: &mut dyn Write) // 普通函数 
fn say_hello<W: Write>(out: &mut W) // 泛型函数

可以明确写出泛型

 say_hello::<File>(&mut local_file)?

同时多个

fn top_ten<T: Debug + Hash + Eq>(values: &Vec<T>) { ... }

where语法

fn run_query<M, R>(data: &DataSet, map: M, reduce: R) -> Results where M: Mapper + Serialize, R: Reducer + Serialize{ ... }

生命周期+范型

fn nearest<'t, 'c, P>(target: &'t P, candidates: &'c [P]) -> &'c P where P: MeasureDistance{}

范型别名:

type PancakeResult<T> = Result<T, PancakeError>;

常量泛型

dot_product::<3>([0.2, 0.4, 0.6], [0., 0., 1.]);

Box包装了一层引用,这样,vec内的存的其实是Box的引用,这样,一个引用的大小区间是固定的,所以在编译期间就知道了。固定大小很重要吗,为什么要在编译期间知道,因为:

对于动态大小类型(如 dyn Trait),由于其大小在编译时未知,无法直接在栈上分配。因此,我们使用堆分配来处理这些类型,并使用固定大小的指针(如 Box)来引用它们。这样,编译器只需知道指针的大小,而不需要知道实际对象的大小。

struct Salad {
    veggies: Vec<Box<dyn Vegetable>>
}

指定泛型

let _ = std::cmp::min::<i32>(3, 4);

实现trait的范型,泛型跟在impl后面 ,对于每个 实现了 Write 的类型 W,这里有一个适用于 W 的 WriteHtml 实现:

impl<W: Write> WriteHtml for W {

泛型中的Self和结构体中的Self

在泛型和特征中,Self 关键字用来指代实现该特征的具体类型。它在定义特征方法时非常有用,尤其是在需要返回实现该特征的类型时。

在结构体和实现块中,Self 关键字用来指代当前的实现类型。它在定义关联函数或方法时非常有用,可以简化代码的书写。

struct MyStruct {
    value: i32,
}

impl MyStruct {
    fn new(value: i32) -> Self { // 这里的 Self 代表 MyStruct
        Self { value } // 这里的 Self 也是 MyStruct
    }

    fn get_value(&self) -> i32 {
        self.value
    }
}

fn main() {
    let instance = MyStruct::new(42);
    println!("The value is: {}", instance.get_value());
}

特型继承:

trait Creature: Visible {}

表示:每个实现了 Creature 的类型也必须实现 Visible 特型。

impl Visible for Broom {
    ...
}
impl Creature for Broom {
    ...
}

子特型不会继承 其超特型的关联项,如果你想调用超特型的方法,那么仍然要保证每 个特型都在作用域内。

trait ParentTrait {
    type AssociatedType;
    fn parent_method(&self);
}

trait ChildTrait: ParentTrait {
    fn child_method(&self);
}

struct MyStruct;

impl ParentTrait for MyStruct {
    type AssociatedType = i32;
    fn parent_method(&self) {
        println!("Parent method");
    }
}

impl ChildTrait for MyStruct {
    fn child_method(&self) {
        println!("Child method");
    }
}

fn main() {
    let instance = MyStruct;
    instance.child_method();
    instance.parent_method(); // 需要显式地调用 ParentTrait 的方法
}

在这个例子中,ChildTrait 继承自 ParentTrait,但 ChildTrait 并没有自动继承 ParentTrait 的关联类型 AssociatedType 或方法 parent_method。如果你想调用 parent_method,你必须显式地将 ParentTrait 带入作用域。

trait ParentTrait {
    type AssociatedType;
    fn parent_method(&self);
}

trait ChildTrait: ParentTrait {
    fn child_method(&self);
}

struct MyStruct;

impl ParentTrait for MyStruct {
    type AssociatedType = i32;
    fn parent_method(&self) {
        println!("Parent method");
    }
}

impl ChildTrait for MyStruct {
    fn child_method(&self) {
        println!("Child method");
        self.parent_method(); // 显式地调用 ParentTrait 的方法
    }
}

fn main() {
    let instance = MyStruct;
    instance.child_method(); // 这将调用 child_method 和 parent_method
}

在这个例子中,ChildTrait 的 child_method 显式地调用了 ParentTrait 的 parent_method。这表明,即使 ChildTrait 继承自 ParentTrait,你仍然需要显式地调用父特征的方法。

范型继承:

fn unknown_words<S: StringSet>(document: &[String], wordlist: &S) -> S {...}

切片引用,切片内是引用

&[&str]

trait type :

impl Iterator for Args {
    type Item = String;
    fn next(&mut self) -> Option<String> {
       Some("good".to_string())
    }
}

它能生成 String 值,因此这个 impl 声明了 type Item = String;下面的用法真的好啊:

fn collect_into_vector<I: Iterator>(iter: I) -> Vec<I::Item> {
    let mut results = Vec::new();
    for value in iter {
        results.push(value);
    }
    results 
}

I指定了范型,但边界是Iterator,因为I是trait,有个Item,可以直接引用I::Item。明确写出 collect_into_vector 的返回类型, 而 Item 关联类型是唯一的途径。但是如果Item想要打印{:?}的话:

fn dump<I>(iter: I) where I: Iterator, I::Item: Debug {

}

如果是String:

fn dump<I>(iter: I) where I: Iterator<Item=String> {
}

Iterator<Item=String> 本身就是一个特型。如果将 Iterator 视为所有迭代器类型的全集,那么 Iterator<Item=String> 就 是 Iterator 的子集:生成 String 的迭代器类型的集合。

fn dump(iter: &mut dyn Iterator<Item=String>) {
    for (index, s) in iter.enumerate() {
        println!("{}: {:?}", index, s);
    }
}

以及:

trait Pattern {
    type Match;
    fn search(&self, string: &str) -> Option<Self::Match>;
}
/// 你可以在字符串中找一个特定的字符
impl Pattern for char {
    type Match = usize;

    /// Match只是找到的字符的位置 
    fn search(&self, string: &str) -> Option<usize> {
        Some(3)
    }
}

trait和struct中的Self

当你为一个结构体实现一个特征时,Self 关键字指的是实现该特征的具体类型。在你的例子中,当你为结构体 Ps 实现特征 MyIteratorTrait 时,Self 关键字指的就是 Ps。


trait MyIteratorTrait<Opp:OpTrait> {
    type Item;
    fn new(t:i32) -> Self;
    fn show_item<I>(&self, t:I) -> Opp where I:Iterator, I::Item:Debug;

}

struct Ps{
    value:i32
}

trait OpTrait{

}

struct Op{name:String}

impl OpTrait for Op {

}

impl MyIteratorTrait<Op> for Ps {
    type Item = String;

    fn new(value:i32) -> Self{
        Ps{value }
    }

    fn show_item<I>(&self, t: I) -> Op
    where
        I: Iterator,
        I::Item: Debug
    {
        // vec![self.value.to_string()]
        Op{name:self.value.to_string()}
    }
}


fn main() {    
    let ps: Ps = Ps::new(32);
    let vecc = vec![32];
    ps.show_item(vecc.into_iter());
}

既然是泛型则能使用泛型相关:

fn print<T: Display>(val: T) {
    println!("{}", val);
}
fn print(val: impl Display) {
    println!("{}", val);
}

使用泛型时允许函数的调用者指定泛型参数的 类型,比如 print::<i32>(42),而如果使用 impl Trait 则不 能这样做。

下面这样也行:

trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;
}