Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rust study - 05 #61

Open
zhuzhh opened this issue Jan 29, 2023 · 0 comments
Open

rust study - 05 #61

zhuzhh opened this issue Jan 29, 2023 · 0 comments

Comments

@zhuzhh
Copy link
Owner

zhuzhh commented Jan 29, 2023

泛型
泛型,为了消除重复

泛型并不会使程序比具体类型运行的慢

Rust 通过在编译时进行泛型代码的 单态化(monomorphization)来保证效率。
单态化是一个通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。

泛型没运行时开销

Trait:定义共同行为
类似于 Java 里的 接口 (interface)

pub trait Summary {
    fn summarize(&self) -> String; // 分号隔开
}

aggregator 库

// src/lib.rs
pub trait Summary {
    fn summarize(&self) -> String;
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

引用

use aggregator::{Summary, Tweet};

fn main() {
    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from(
            "of course, as you probably already know, people",
        ),
        reply: false,
        retweet: false,
    };

    println!("1 new tweet: {}", tweet.summarize());
}

默认行为

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}
pub trait Summary {
    fn summarize_author(&self) -> String;

    fn summarize(&self) -> String {
        format!("(Read more from {}...)", self.summarize_author())
    }
}

impl Summary for Tweet {
    fn summarize_author(&self) -> String {
        format!("@{}", self.username)
    }
}

// 调用 summarize 方法时,也会调用summarize_author方法

trait 作为参数

生命周期

let r;
{
    let x = 5;
    r = &x;
}
println!("r: {}", r);

会报错,x 在离开作用域时就会销毁,外部不能在使用其引用了

函数中的泛型生命周期

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

以上代码会报错,报错原因是 longest return 了一个借来的值,但是函数签名没有明确借的是 x 还是 y
确实,longest 函数 x 还是 y,只有在运行时才能确定

为解决以上问题,可使用泛型生命周期参数来定义引用间的关系,以便借用检查器可以进行分析

生命周期注解并不改变任何引用的生命周期的长短
相反它们描述了多个引用生命周期相互的关系,而不影响其生命周期

基本语法:以撇号(')开头

&i32        // 引用
&'a i32     // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用

单个的生命周期注解本身没有多少意义,因为生命周期注解告诉 Rust 多个引用的泛型生命周期参数如何相互联系的

例如如果函数有一个生命周期 'ai32 的引用的参数 first。还有另一个同样是生命周期 'ai32 的引用的参数 second。这两个生命周期注解意味着引用 firstsecond 必须与这泛型生命周期存在得一样久

eg:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

两个参数,他们都是与生命周期 'a 存在一样长的字符串 slice,返回一个同样与生命周期 'a 一样长的字符串 slice
实际含义是 longest 函数返回的引用的生命周期 与 参数引用的值的生命周期的较小者一致
参数 xy 哪个生命周期短,返回值的生命长度和其保持一致

注意 longest 函数并不需要知道 x 和 y 具体会存在多久,而只需要知道有某个可以被 'a 替代的作用域将会满足这个签名
(后半句不是很理解)

生命周期注解只会出现在函数签名中,而不存在于函数体中的任何代码中
让函数签名包含生命周期约定意味着 Rust 编译器的工作变的更简单了

eg:

fn main() {
    let string1 = String::from("long string is long");

    {
        let string2 = String::from("xyz");
        let result = longest(string1.as_str(), string2.as_str());
        println!("The longest string is {}", result);
    }
}

正确输出 "long string is long"

bad case

fn main() {
    let string1 = String::from("long string is long");
    let result;
    {
        let string2 = String::from("xyz");
        result = longest(string1.as_str(), string2.as_str());
    }
    println!("The longest string is {}", result);
}

result 的生命周期和 string2 一致(string2 的生命周期比 string1短),所以函数返回是寿命最短的那个

fn longest<'a>(x: &'a str, y: &str) -> &'a str {
    x
}

如果函数总是返回第一个参数,如上代码,则必须指定 参数 x 和返回值注解,否则会报错

如果返回一个新生成的变量,即便指定生命周期,也会编译失败

fn longest<'a>(x: &str, y: &str) -> &'a str {
    let aa = String::from("really long string");
    aa.as_str()
}

aa 在 函数执行完毕后就被清空了,而我们尝试从函数返回一个 aa 的引用
无法指定生命周期参数来改变悬垂引用

最好的解决方案是返回一个有所有权的数据类型而不是一个引用,这样函数调用者就需要负责清理这个值

fn longest() -> str {
    let aa = String::from("really long string");
    aa.as_str() // 返回非引用的值
}

结构体中使用生命周期注解

struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt {
        part: first_sentence,
    };
}

生命周期消除

RAII 的思想是:资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配,同时由析构函数完成资源的释放。在这种要求下,只要对象能正确的析构,就不会出现资源泄露问题。

@zhuzhh zhuzhh changed the title rust-study - 05 rust study - 05 Jan 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant