Rust在线运行

版本:

所属目录
点击了解高性能代码运行API
运行结果
教程手册
代码仓库
极速运行
终端运行
图形+终端

                        
以下是用户最新保存的代码
first programe! 发布于:2024-10-25 16:46 ### VecDeque 复制测试 发布于:2024-04-23 09:37 ## 输入三个整数x,y,z,请把这三个数由小到大输出。 发布于:2024-03-03 11:45 # rust slice 发布于:2024-02-20 13:49 rust学习 发布于:2024-01-04 08:20 Rust hello world 发布于:2024-01-01 23:49 # Rust的常用迭代器适配器 ## map 可以用闭包将迭代器里的每个元素应用闭包里自定义的逻辑,从而生成处理后的元素迭代器,可以应用于数据处理与提取. ## filter 可以使用闭包过滤迭代器里的元素,只挑选出符合要求的元素组成新的迭代器返回。 ## fold ## zip ## chunks ## Chain ## all ## any ## windows ## cycle 发布于:2023-12-27 17:58 # 箱子、栈和堆 在 Rust 中,所有值默认都是栈分配的。通过创建 Box<T>,可以把值装箱(boxed)来使它在堆上分配。箱子(box,即 Box<T> 类型的实例)是一个智能指针,指向堆分配的 T 类型的值。当箱子离开作用域时,它的析构函数会被调用,内部的对象会被销毁,堆上分配的内存也会被释放。 被装箱的值可以使用 * 运算符进行解引用;这会移除掉一层装箱。 发布于:2023-12-27 17:40 测试rust的值域安全性 发布于:2023-12-12 09:52 书本的内容 发布于:2023-11-17 17:25 rust代码测试 发布于:2024-07-09 15:44 Learn Rust 发布于:2023-11-09 17:33 Rust学习使用 发布于:2023-05-21 11:21 exercise trait 发布于:2023-04-16 19:42 闭包的捕获 发布于:2023-01-28 16:32 Rust 结构体相关代价 发布于:2022-12-29 09:22 [package] name = "hello_rust" version = "0.1.0" authors = ["gress"] edition = "2018" [dependencies] anyhow= “0.1” 发布于:2022-12-06 20:09 第一个Rust程序 发布于:2022-06-20 00:11 开始学习rust 发布于:2022-05-30 13:51 enum sample 发布于:2022-02-24 15:03 泛型、特性与生命周期协同作战里的实例如何使用 发布于:2022-01-02 16:25 Rust第四章---所有权 发布于:2021-12-31 15:31 Rust第三章-常见编程概念 发布于:2021-12-31 13:16 Hello World Rust 发布于:2021-02-11 19:18 [更多]
显示目录

泛型与特性



学习嵌入式的绝佳套件,esp8266开源小电视成品,比自己去买开发板+屏幕还要便宜,省去了焊接不当搞坏的风险。 蜂鸣版+触控升级仅36元,更强的硬件、价格全网最低。

点击购买 固件广场

Rust 泛型与特性

泛型是一个编程语言不可或缺的机制。

C++ 语言中用"模板"来实现泛型,而 C 语言中没有泛型的机制,这也导致 C 语言难以构建类型复杂的工程。

泛型机制是编程语言用于表达类型抽象的机制,一般用于功能确定、数据类型待定的类,如链表、映射表等。

在函数中定义泛型

这是一个对整型数字选择排序的方法:

实例

fn max(array: &\[i32\]) \-> i32 {  
    let mut max\_index \= 0;  
    let mut i \= 1;  
    while i < array.len() {  
        if array\[i\] \> array\[max\_index\] {  
            max\_index \= i;  
        }  
        i += 1;  
    }  
    array\[max\_index\]  
}  

fn main() {  
    let a \= \[2, 4, 6, 3, 1\];  
    println!("max = {}", max(&a));  
}

运行结果:

max \=  6

这是一个简单的取最大值程序,可以用于处理 i32 数字类型的数据,但无法用于 f64 类型的数据。通过使用泛型我们可以使这个函数可以利用到各个类型中去。但实际上并不是所有的数据类型都可以比大小,所以接下来一段代码并不是用来运行的,而是用来描述一下函数泛型的语法格式:

实例

fn max<T\>(array: &\[T\]) \-> T {  
    let mut max\_index \= 0;  
    let mut i \= 1;  
    while i < array.len() {  
        if array\[i\] \> array\[max\_index\] {  
            max\_index \= i;  
        }  
        i += 1;  
    }  
    array\[max\_index\]  
}

结构体与枚举类中的泛型

在之前我们学习的 Option 和 Result 枚举类就是泛型的。

Rust 中的结构体和枚举类都可以实现泛型机制。

struct Point { x: T, y: T } 这是一个点坐标结构体,T 表示描述点坐标的数字类型。我们可以这样使用:

let p1 = Point {x: 1, y: 2};
let p2 = Point {x: 1.0, y: 2.0};

使用时并没有声明类型,这里使用的是自动类型机制,但不允许出现类型不匹配的情况如下:

let p = Point {x: 1, y: 2.0};

x 与 1 绑定时就已经将 T 设定为 i32,所以不允许再出现 f64 的类型。如果我们想让 x 与 y 用不同的数据类型表示,可以使用两个泛型标识符:

struct Point<T1, T2> {
    x: T1,
    y: T2
}

在枚举类中表示泛型的方法诸如 Option 和 Result:

enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

结构体与枚举类都可以定义方法,那么方法也应该实现泛型的机制,否则泛型的类将无法被有效的方法操作。

实例

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

impl<T\> Point<T\> {  
    fn x(&self) \-> &T {  
        &self.x  
    }  
}  

fn main() {  
    let p \= Point { x: 1, y: 2 };  
    println!("p.x = {}", p.x());  
}

运行结果:

p.x \=  1

注意,impl 关键字的后方必须有 ,因为它后面的 T 是以之为榜样的。但我们也可以为其中的一种泛型添加方法:

impl Point<f64> {
    fn x(&self) -> f64 {
        self.x
    }
}

impl 块本身的泛型并没有阻碍其内部方法具有泛型的能力:

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,
        }
    }
}

方法 mixup 将一个 Point 点的 x 与 Point 点的 y 融合成一个类型为 Point 的新点。


特性

特性(trait)概念接近于 Java 中的接口(Interface),但两者不完全相同。特性与接口相同的地方在于它们都是一种行为规范,可以用于标识哪些类有哪些方法。

特性在 Rust 中用 trait 表示:

trait Descriptive  { fn describe(&self)  \->  String;  }

Descriptive 规定了实现者必须有是 describe(&self) -> String 方法。

我们用它实现一个结构体:

实例

struct Person {  
    name: String,  
    age: u8  
}  

impl Descriptive for Person {  
    fn describe(&self) \-> String {  
        format!("{} {}", self.name, self.age)  
    }  
}

格式是:

impl <特性名>  for  <所实现的类型名>

Rust 同一个类可以实现多个特性,每个 impl 块只能实现一个。

默认特性

这是特性与接口的不同点:接口只能规范方法而不能定义方法,但特性可以定义方法作为默认方法,因为是"默认",所以对象既可以重新定义方法,也可以不重新定义方法使用默认的方法:

实例

trait Descriptive {  
    fn describe(&self) \-> String {  
        String::from("\[Object\]")  
    }  
}  

struct Person {  
    name: String,  
    age: u8  
}  

impl Descriptive for Person {  
    fn describe(&self) \-> String {  
        format!("{} {}", self.name, self.age)  
    }  
}  

fn main() {  
    let cali \= Person {  
        name: String::from("Cali"),  
        age: 24  
    };  
    println!("{}", cali.describe());  
}

运行结果:

Cali  24

如果我们将 impl Descriptive for Person 块中的内容去掉,那么运行结果就是:

\[Object\]

特性做参数

很多情况下我们需要传递一个函数做参数,例如回调函数、设置按钮事件等。在 Java 中函数必须以接口实现的类实例来传递,在 Rust 中可以通过传递特性参数来实现:

fn output(object: impl Descriptive) {
    println!("{}", object.describe());
}

任何实现了 Descriptive 特性的对象都可以作为这个函数的参数,这个函数没必要了解传入对象有没有其他属性或方法,只需要了解它一定有 Descriptive 特性规范的方法就可以了。当然,此函数内也无法使用其他的属性与方法。

特性参数还可以用这种等效语法实现:

fn output<T: Descriptive>(object: T) {
    println!("{}", object.describe());
}

这是一种风格类似泛型的语法糖,这种语法糖在有多个参数类型均是特性的情况下十分实用:

fn output_two<T: Descriptive>(arg1: T, arg2: T) {
    println!("{}", arg1.describe());
    println!("{}", arg2.describe());
}

特性作类型表示时如果涉及多个特性,可以用 + 符号表示,例如:

fn notify(item: impl Summary + Display)
fn notify<T: Summary + Display>(item: T)

注意:仅用于表示类型的时候,并不意味着可以在 impl 块中使用。

复杂的实现关系可以使用 where 关键字简化,例如:

fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U)

可以简化成:

fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone,
          U: Clone + Debug

在了解这个语法之后,泛型章节中的"取最大值"案例就可以真正实现了:

实例

trait Comparable {  
    fn compare(&self, object: &Self) \-> i8;  
}  

fn max<T: Comparable\>(array: &\[T\]) \-> &T {  
    let mut max\_index \= 0;  
    let mut i \= 1;  
    while i < array.len() {  
        if array\[i\].compare(&array\[max\_index\]) \> 0 {  
            max\_index \= i;  
        }  
        i += 1;  
    }  
    &array\[max\_index\]  
}  

impl Comparable for f64 {  
    fn compare(&self, object: &f64) \-> i8 {  
        if &self \> &object { 1 }  
        else if &self \== &object { 0 }  
        else { \-1 }  
    }  
}  

fn main() {  
    let arr \= \[1.0, 3.0, 5.0, 4.0, 2.0\];  
    println!("maximum of arr is {}", max(&arr));  
}

运行结果:

maximum of arr is  5

Tip: 由于需要声明 compare 函数的第二参数必须与实现该特性的类型相同,所以 Self (注意大小写)关键字就代表了当前类型(不是实例)本身。

特性做返回值

特性做返回值格式如下:

实例

fn person() \-> impl Descriptive {  
    Person {  
        name: String::from("Cali"),  
        age: 24  
    }  
}

但是有一点,特性做返回值只接受实现了该特性的对象做返回值且在同一个函数中所有可能的返回值类型必须完全一样。比如结构体 A 与结构体 B 都实现了特性 Trait,下面这个函数就是错误的:

实例

fn some\_function(bool bl) \-> impl Descriptive {  
    if bl {  
        return A {};  
    } else {  
        return B {};  
    }  
}

有条件实现方法

impl 功能十分强大,我们可以用它实现类的方法。但对于泛型类来说,有时我们需要区分一下它所属的泛型已经实现的方法来决定它接下来该实现的方法:

struct A<T> {}

impl<T: B + C> A<T> {
    fn d(&self) {}
}

这段代码声明了 A 类型必须在 T 已经实现 B 和 C 特性的前提下才能有效实现此 impl 块。

由JSRUN为你提供的Rust在线运行、在线编译工具
        JSRUN提供的Rust 在线运行,Rust 在线运行工具,基于linux操作系统环境提供线上编译和线上运行,具有运行快速,运行结果与常用开发、生产环境保持一致的特点。
yout