Rust基础学习笔记(一):Generic Types, Traits, and Lifetime
这是通过官方文档学习Rust基础的第一篇博客,也是笔者的第一篇技术博客,还蛮有纪念意义的。
学习Rust的原因是在学习前端的过程中需要一门后端开发语言,经建议准备入手Rust。笔者在写这篇博客之前已经阅读了前九章的内容,然而苦于没有实践,记忆不牢,故打算从第十章开始用博客记录以加深记忆。这一系列大概会以一章一篇的规模更新,阅读完官方文档之后的其他内容也许会脱离这一系列。
第十章内容涉及泛型、特性与生命周期。目的是精简代码结构,基本步骤包括
- 找出重复代码;
- 在声明中确定接受与返回值的类型,将代码提取到函数体中;
- 在主函数中调用该函数。
泛型
我们可以利用泛型来定义函数、类方法、枚举和结构体。
在函数中使用泛型
fn largest<T>(list : &[T]) -> T { ... }
在结构体中使用泛型
struct Point<T> { x: T, y: T, }
使用多个泛型
struct Point<T, U> { x: T, y: U, }
在枚举中使用泛型
以Option<T>与Result<T>为例:
enum Option<T> { Some(T), None, } enum Result<T, E>{ Ok(T), Err(E), }
在类方法中使用泛型
struct Point<T, U>{ x: T, y: U, } impl<T, U> Point<T, U>{ fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W>{ Point { x: self.x, y: other.y, } } }
泛型与运行效率
泛型的使用不会降低程序运行的效率,对于Rust而言它只会将泛型替换成确切的形式。这个过程称作Monomorphization
特性
可以与其他类型共享的方法集合,在其它语言中被称为Interface(接口)。
定义一个特性
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 trait Summary{ fn summarize(&self) -> String { String::from("(Read more...)") } } impl Summary for NewsArticle {}
也可以通过默认行为调用其他的方法。不过这个方法在实现的时候需要具体定义。
pub trait Summary{ fn summarize_author(&self) -> String; fn summarize(&self) -> String { String::from("(Read more from {}...)", summarize_author()) } }
impl Summary for tweet{
fn summarize_author(&self) -> String{
format!("@{}",&self.username)
}
}
特性做参数
对所有实现了某特性的类型提供统一的函数,并接受这些类型作为参数。在声明时只需要声明被实现的特性即可。
pub fn notify(item :&impl Summary){ println!("Breaking News! {}", item.summarize()); }
使用未实现指定特性的类型做参数时,报错。
特性绑定语法
等同于特性做参数时的用法,而某些时候能精简代码,或者对类型作出限制:
pub fn notify(item1: &impl Summary, item2: &impl Summary) { ... } //允许两个参数拥有不同类型 pub fn notify<T: Summary> (item1: &T, item2: &T){ ... }
//强制两个参数拥有相同类型
用“+”绑定多个特性
同样有两种写法
pub fn notify(item:&(impl Summary + Display)) { ... } //等同于 pub fn notify<T: Summary + Display>(item: &T) { ... }
Where语法简化特性绑定
提高代码可读性的一种手段
fn some_function<T, U>(item1: &T, item2: &U) -> i32 where T = Display + Summary, U = Clone + Summary { ... }
返回Trait
用来返回某种实现了指定特性的类型。主要用在闭包和迭代器里面(以后讨论)
fn ret_impl() -> impl Summary
{
    Tweet{
        ...
        }
}
*这个方法只能用来返回单个种类的值,如果出现多种返回值的可能类型,程序不会通过编译。
有条件的实现特性
只会对满足条件的类型添加某种特性:
struct Stru<T>{ ... } impl<T: Some> Stru<T>{ ... } //或者选择全部 impl<T: Some> Trait_name for T { ... }
生命周期
防止垂悬引用
当引用的生命周期长于被引用变量时,垂悬引用报错!
{ let r; { let x = 1; r = &x; } //x无了 println!("x = {}" ,r); //报错,垂悬引用 }
生命周期注释
本质上用来绑定返回值的生命周期以保证内存安全
不带注释的时候,编译器不确定引用返回值所在的生命周期,因而报错:
fn longer(str1: &str, str2: &str) ->&str { if str1.len > str.2len { str1 } else { str2 } } //报错:返回值在哪个区间里?
通过添加生命周期注释可以解决这个问题:
fn longer<'a>(str1: &'a str, str2: &'a str) ->&'a str { if str1.len > str.2len { str1 } else { str2 } } //通过编译:特定过的生命周期,选定为&str1和&str2的最小者
返回值只能在 'a 所指定的范围内生效。
从生命周期的角度理解程序
- 当某个参数和返回值的生命周期没有关系时不要加注释
- 返回的引用必须和参数中的至少一者拥有相同的生命周期注释(也可以与函数中声明的变量相同,不过会造成垂悬引用)
在结构体中运用生命周期注释
可以用来确定结构体变量的声明周期:
struct Im<'a>{ part: &'a str, } fn main(){ let novel = String::from("...."); let first_sen = novel.spilt('.').next().expect("..."); let i = Im{ part : first_sen; }; }
这里i的声明周期要小于其引用的novel。
被省略的生命周期注释
随着人们发现一些相同的需要注释的情况,这些情况已经在Rust的版本更新中写入源代码,因此可以在一些具体的情况下省略生命周期注释。
随着人们对Rust的开发,需要用到生命周期注释的情况越来越少。
目前有三大类情况可以省略注释:
所有的参数都拥有各自的生命周期注释:
fn example<'a, 'b> (item1 &'a i32, item2 &'b i32) { ... }
标红可省略,但是会在编译阶段自动添加。
单个参数的声明周期注释用于所有输出
fn example<'a> (x: &'a i32) -> &'a i32{ ... }
同上
(类方法中)&self 或 &mut self被用于所有输出
impl<'a> Im<'a>{ fn announce_and_return_part(&self, announcement: &str) -> &str{ println!("{}",announcement); self.part } }
静态生命周期
拥有静态生命周期的变量将在程序运行阶段一直保持有效。字符串字面值默认拥有该属性。
let s : &'static str = "Static Lifetime";
另
由于状态不佳,这一章的学习占用了整整一下午和一晚上的时间,看的还是云里雾里。由于笔者英语水平有限,且尚为IT初学者,难免有许多误解迷惑之处,日后回顾博客的时候想必会加以修改。
另外CNBLOGS没有Rust语法高亮,代码部分可读性也惨不忍睹,仅能供个人参考。若这篇文章有幸能被你看到,还请不吝赐教。
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号