首页 > 其他分享 >Rust简易入门(六)

Rust简易入门(六)

时间:2024-04-18 16:12:24浏览次数:23  
标签:入门 Overview self 简易 let Rust println fn impl

Trait 特质

Trait是一种定义方法签名的机制,特质允许你定义一组方法的签名,但可以不提供具体的方法实现

任何类型都可以实现特质,只要他们提供了特质中定义的所有方法。这是的你可以为不同类型提供相同的行为

  1. 内置常量:const,整个生命周期都是有效的

  2. 默认实现

  3. 多重实现:类型可以实现多个trait,可以将不同行为组合在一起

  4. trait边界:在泛型代码中,使用特质作为类型约束

  5. trait alias:可以创建简介的别名

trait Greeter {
    fn greet(&self);
    fn hello() {
        println!("hello");
    }
}

struct Person {
    name: String,
}

impl Greeter for Person {
    fn greet(&self) {
        println!("{}", self.name);
    }
}



fn main(){
    let person = Person {
        name: "moguw".to_owned(),
    };
    
    Person::hello();
    person.greet();
}

Trait Object 与 Box

Trait Object

  1. 在运行时动态分配的对象
    运行时泛型
    比泛型要灵活的多

  2. 可以在集合中混入不同的类型对象
    更容易处理相似的数据

  3. 有一些小小的性能损耗

dyn关键字

dyn是Rust中的关键字,用于声明trait object的类型。trait object是实现了trait的类型的实例,但其具体类型在编译时是未知的。因此为了让编译器知道我们正在处理的是trait object,我们需要在trait名称前面加上dyn关键字

dyn关键字的作用是:指示编译器处理trait object

Rust中数据传输的三种形式

不可变引用 &dyn Trait

可变引用 &mut dyn Trait

Move与以所有权转移:特指需要用Box实现Move,如果你需要在函数调用之间传递特质的所有权,并且希望避免在栈上分配大量的内存,可以使用Box

特质与Box

创建trait object的三种方式

let o = Object{}
let o_obj: &dyn Object = &o
let o_obj: &dyn Object = &Object {};
let o_obj: Box<dyn Object> = Box::new(Object{})
// trait 不可变引用
struct Obj {}

trait Overview{
    fn overview(&self) -> String {
        String::from("overview")
    }
}

impl Overview for Obj{
    fn overview(&self) -> String {
        String::from("Obj")
    }
}

// 不可变引用
fn call_obj(item: &impl Overview) {
    println!("Overview {}", item.overview());
}

// Move
fn call_obj_box(item: Box<dyn Overview>) {
    println!("Overview {}", item.overview());
}

trait Sale {
    fn amount(&self) -> f64;
}

struct Common(f64); // 原始金额
impl Sale for Common{
    fn amount(&self) -> f64 {
        self.0
    }
}

struct TenDiscount(f64);
impl Sale for TenDiscount {
    fn amount(&self) -> f64 {
        self.0 - 10.
    }
}

struct TenPercentDiscount(f64);
impl Sale for TenPercentDiscount {
    fn amount(&self) -> f64 {
        self.0 * 0.9
    }
}

fn calculate(sales: &Vec<Box<dyn Sale>>) -> f64 {
    sales.iter().map(|sale| sale.amount()).sum()
}

fn main() {
    let a = Obj{};
    call_obj(&a);
    println!("{}", a.overview());
    let b_a = Box::new(Obj {});
    call_obj_box(b_a);  // 所有权转移
    
    let c: Box<dyn Sale> = Box::new(Common(100.));
    let d: Box<dyn Sale> = Box::new(TenDiscount(100.));
    let e: Box<dyn Sale> = Box::new(TenPercentDiscount(100.));
    
    let sales = vec![c, d, e];  // : Vec<Box<dyn Sale>>
    
    println!("pay {}", calculate(&sales));
}

Trait Object 与 泛型

泛型与impl不同的写法

// 可以是不同类型
fn call(item1: &impl Trait, item2: &impl Trait);
// 一定是相同类型
fn call_generic<T: Trait>(item1: &T, item2: &T);

// multiple trait bound
fn call(item1: &(impl Trait+AnotherTrait));
fn call_genertic<T: Trait+AnotherTrait>(item: &T);
trait Overview {
    fn overview(&self) -> String {
        String::from("Course")
    }
}

trait Another {
    fn hell(&self) {
        println!("Welcome to hell");
    }
}

struct Course {
    headline: String,
    author: String,
}

impl Overview for Course {}
impl Another for Course {}

struct AnotherCourse {
    headline: String,
    author: String,
}

impl Overview for AnotherCourse {}

fn call_overview(item: &impl Overview) {
    println!("Overview");
}

fn call_overview_generic<T: Overview>(item: &T) {
    println!("Overview");
}

fn call_overviewT(item1: &impl Overview, item2: &impl Overview) {
    println!("Overview {}",item1.overview());
    println!("Overview {}",item2.overview());
}

fn call_overviewTT<T: Overview>(item1: &T, item2: &T) {
    println!("Overview {}",item1.overview());
    println!("Overview {}",item2.overview());
}

// 多绑定
fn call_mul_bind(item: &(impl Overview + Another)) {
    println!("Overview {}",item.overview());
    item.hell();
}

// 多绑定
fn call_mul_bindT<T>(item: &T) 
where 
    T: Overview+Another
{
    println!("Overview {}",item.overview());
    item.hell();
}

fn main() {
    let c1 = Course{
        headline: "11".to_owned(),
        author: "22".to_owned()
    };
        
    let c2 = AnotherCourse{
        headline: "11".to_owned(),
        author: "22".to_owned()
    };
    
    let c3 = Course{
        headline: "11".to_owned(),
        author: "22".to_owned()
    };
    
    call_overview(&c1);
    call_overview_generic(&c1);
    
    println!("------");
    
    call_overviewT(&c1, &c2);
    call_overviewTT(&c1, &c3);
    
    println!("------");
    call_mul_bind(&c1);
    call_mul_bindT(&c3);
}

重载操作符

只需要实现相对的特质即可

use std::ops::Add;

// 编译时确定
#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

// T 可以执行相加的操作
impl<T> Add for Point<T> 
where 
    T: Add<Output = T>
{
    type Output = Self;
    fn add(self,rhs: Self) -> Self::Output{
        Point {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

fn main(){
    let i1 = Point {
        x: 0,
        y: 0,
    };
    let i2= Point {
        x: 1,
        y: 1,
    };
    let sum = i1 + i2;
    println!("{:?}", sum);
}

Trait多态和继承

Rust并不支持传统的继承的概念,但是可以在特质中通过层级化来完成需求

Rust选择了一种函数式编程的范式,即“组合与委托”而并不是继承

编程语言的大势也是组合由于继承

  • 多态是面向对象编程中的一个重要概念,指的是同一个方法调用可以根据对象的不同类型而表现出不同的行为。简单来说,多态允许一个接口或方法在不同的上下文中表现出不同的行为。这样做的好处是可以提高代码的灵活性和可扩展性,使得代码更易于维护和理解

  • Rust中的多态无处不在

use std::collections::VecDeque;

trait Driver {
    fn drive(&self);
}
struct Car;
impl Driver for Car {
    fn drive(&self) {
        println!("Car is driving");
    }
}

struct SUV;
impl Driver for SUV {
    fn drive(&self) {
        println!("SUV is driving");
    }
}

fn road(vehicle: &dyn Driver) {
    vehicle.drive();
}   

trait Queue {
    fn len(&self) -> usize;
    fn push_back(&mut self, n: i32);
    fn pop_front(&mut self) -> Option<i32>;
}

trait Double: Queue {
    fn push_front(&mut self, n: i32);
    fn pop_back(&mut self) -> Option<i32>;
}

#[derive(Debug)]
struct list {
    data: VecDeque<i32>,
}

impl list {
    fn new() -> Self {
        let data = VecDeque::<i32>::new();
        Self { data }
    }
}


impl Double for list {
    fn push_front(&mut self, n:i32) {
        self.data.push_front(n)
    }
    
    fn pop_back(&mut self) -> Option<i32> {
        self.data.pop_back()
    }
}

impl Queue for list {
    fn len(&self) -> usize {
        self.data.len()
    }
    
    fn push_back(&mut self, n: i32) {
        self.data.push_back(n)
    }
    
    fn pop_front(&mut self) -> Option<i32> {
        self.data.pop_front()
    }
    
}

fn main() {
    road(&Car);
    road(&SUV);
    
    let mut l = list::new();
    l.push_back(1);
    l.push_front(0);
    println!("{:?}", l);
    
    l.push_front(2);
    println!("{:?}", l);
    
    l.push_back(2);
    println!("{:?}", l);
    
    println!("{}", l.pop_back().unwrap());
    println!("{:?}", l);

}

常见的Trait

#[derive(Debug, Clone, Copy)]
enum Race {
    White,
    Yellow,
    Black
}

impl PartialEq for Race {
    fn eq(&self, other: &Self) -> bool {
        match(self, other) {
            (Race::White, Race::White) => true,
            (Race::Yellow, Race::Yellow) => true,
            (Race::Black, Race::Black) => true,
            _ => false,
        }
    }
}

#[derive(Debug, Clone)]
struct User {
    id: u32,
    name: String, // String不实现COpy
    race: Race,
}

impl PartialEq for User {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id && self.name == other.name && self.race == other.race
    }
}

fn main() {
    let user = User {
        id: 3,
        name: "John".to_owned(),
        race: Race::Yellow,
    };
    
    println!("{:#?}", user);
    
    let user1 = user.clone();
    println!("{:#?}", user1);
    
    println!("{:#?}", user==user1);
}

标签:入门,Overview,self,简易,let,Rust,println,fn,impl
From: https://www.cnblogs.com/moguw/p/18143717/rust-base-6

相关文章

  • Spring Security快速入门
    使用SpringBoot+SpringSecurity整合,先定义一个空项目,主要为项目里面各个模块提供依赖,空项目依赖如下:<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.18</version>......
  • vue3+elementplus+axios+router的入门项目总结
    一、使用vite方式创建项目:1、创建空文件夹,用vscode打开空文件夹,终端上运行如下命令$npminitvite-app[项目名]:初始化项目$cd[项目名]:进入项目$npminstall:安装项目依赖$npmrundev:启动项目2、启动项目后会出现访问地址: 3、进入访问地址: 二、引入elementpuls......
  • OpenTelemetry入门看这一篇就够了
    分布式跟踪可以帮助查看整个请求过程中服务之间的交互,并可以让我们深入了解系统中请求的整个生命周期。它帮助我们发现应用程序中的错误、瓶颈和性能问题。OpenTelemetry可以用于从应用程序收集数据。它是一组工具、API和SDK集合,我们可以使用它们来检测、生成、收集和导出遥测......
  • css入门
    目录CSS入门css简介导入方式选择器属性盒子模型浮动定位CSS入门css简介ps:学习此内容前,建议先过一边HTML入门,本文档的使用方法和HTML入门是一样的,就不过多赘述了CSS(CascadingStyleSheets)是一种用于定义网页样式和布局的样式表语言。(中文名是层叠样式表)HTML负责定义......
  • vue3 快速入门系列 —— 组件通信
    vue3快速入门系列-组件通信组件通信在开发中非常重要,通信就是你给我一点东西,我给你一点东西。本篇将分析vue3中组件间的通信方式。Tip:下文提到的绝大多数通信方式在vue2中都有,但是在写法上有一些差异。准备环境在vue3基础上进行。新建三个组件:爷爷、父亲、孩子A、......
  • [Rust] Intro Lifetimes
    Thefollowingcodehascompilererror:fnjazz(years:&[i64])->Releases{leteighties:[i64]=&years[0..2];letnineties:[i64]=&years[2..4];Releases{years,eighties,nineties,}}let......
  • CMake 入门教程
    什么是CMake你或许听过好几种Make工具,例如 GNUMake ,QT的 qmake ,微软的 MSnmake,BSDMake(pmake),Makepp,等等。这些Make工具遵循着不同的规范和标准,所执行的Makefile格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果......
  • 2.JAVA入门 了解JAVA 配置环境
    Java入门Java特性和优势简单性:Java语言设计简洁,易于学习和使用。它摒弃了许多复杂的特性和语法,使得编程变得更加直观和容易上手。面向对象:Java是一种纯粹的面向对象编程语言,所有的代码都以类和对象的形式组织。这种面向对象的特性使得代码更加模块化、可重用性更高,并且更容易......
  • 前端【小程序】01-入门篇【注册小程序账号】【开发环境搭建】
    小程序的优势: 学习内容: 两部分内容:1、组件、配置、生命周期、事件处理、数据渲染、API、自定义组件、VantUI、分包加载等2、通告管理、用户管理、房屋管理、报修管理、访客管理等各个功能模块一、注册小程序账号微信公众平台1、在微信公众平......
  • web server apache tomcat11-01-官方文档入门介绍
    前言整理这个官方翻译的系列,原因是网上大部分的tomcat版本比较旧,此版本为v11最新的版本。开源项目同时也为从零手写实现tomcat提供一些基础和特性的思路。minicat别称【嗅虎】心有猛虎,轻嗅蔷薇。系列文章webserverapachetomcat11-01-官方文档入门介绍webserve......