Skip to content

Latest commit

 

History

History
434 lines (363 loc) · 7.41 KB

L03-generics-traits.org

File metadata and controls

434 lines (363 loc) · 7.41 KB

CIS198 Lecture 3: 泛型和 Trait

泛型

泛型入门

enum Result {
    Ok(String),
    Err(String),
}
  • T / E 表示泛型
enum Result<T, E> {
    Ok(T),
    Err(E),
}

泛型例子

// 非泛型,直接类型
struct Point {
    x: i32,
    y: i32,
}

// T 泛型: T: i32/i64/f32
struct Point<T> {
    x: T,
    y: T,
}

enum List<T> {
    Nil,
    Cons(T, Box<List<T>>),
}

标准库中 Result 的泛型设计

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

impl<T, E> Result<T, E> {
    fn is_ok(&self) -> bool {
        match *self {
            Ok(_) => true,
            Err(_) => false,
        }
    }
}
error: Could not compile `cargo8I6mnS`.

Trait

简单说明

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

struct Line {
    from: Point,
    to: Point,
}

// Trait 类似于 Java 的接口或 Haskell 的 typeclass
trait PrettyPrint {
    fn format(&self) -> String;
}

// 实现 Trait
impl PrettyPrint for Point {
    fn format(&self) -> String {
        format!("({},{})", self.x, self.y)
    }
}

impl PrettyPrint for Line {
    fn format(&self) -> String {
        format!("[{}->{}]", self.from.format(), self.to.format())
    }
}

fn main() {
    let p0 = Point { x: 0, y: 0 };
    println!("p0 = {}", p0.format());
    let p1 = Point { x: 1, y: 1 };
    let line = Line { from: p0, to: p1 };
    println!("line = {}", line.format());

    // let p1 = Point{x:1, y:0};
    // println!("{}", p0.equals(p1));
}
p0 = (0,0)
line = [(0,0)->(1,1)]

泛型的 Trait Bound

// 范围限定
fn cloning_machine<T: Clone>(t: T) -> (T, T) {
    (t.clone(), t.clone())
}

fn cloning_machine<T>(t: T) -> (T, T) where T: Clone {
    (t.clone(), t.clone())
}

标准库的 PrettyPrint

// Trait 类似于 Java 的接口或 Haskell 的 typeclass
trait PrettyPrint {
    fn format(&self) -> String;
}

// 使用标准库中的 Result
// #[derive(Debug)]
// enum Result<T, E> {
//     Ok(T),
//     Err(E),
// }

impl<T, E> PrettyPrint for Result<T, E>
where
    T: PrettyPrint,
    E: PrettyPrint,
{
    fn format(&self) -> String {
        match self {
            Ok(t) => format!("Ok({})", t.format()),
            Err(e) => format!("Err({})", e.format()),
        }
    }
}

trait Equals {
    fn equals(&self, other: &Self) -> bool;
}

impl<T, E> Equals for Result<T, E>
where
    T: Equals,
    E: Equals,
{
    fn equals(&self, other: &Self) -> bool {
        match (self, other) {
            (Ok(t1), Ok(t2)) => t1.equals(&t2),
            (Err(e1), Err(e2)) => e1.equals(&e2),
            _ => false,
        }
    }
}

fn main() {
    let ok1:Result::<String, String> = Result::Ok("1".to_string());
    let ok2 = Result::Ok::<String, String>("1".to_string());
    println!("{:?}", ok1);
    println!("{:?}", ok2);

    // println!("{:?}", ok1.equals(&ok2));
}
Ok("1")
Ok("1")

继承

trait 的继承

trait Parent {
    fn foo(&self) {
        //
    }
}

trait Child: Parent {
    fn bar(&self) {
        self.foo();
        //
    }
}

默认方法实现

trait AAA {
    fn foo(&self) -> bool {
       true
    }
}

派生

派生入门

  • 通过 #[derive(...)] 指定需要派生的 trait
  • 如果有继承关系,需要同时派生其父 trait
#[derive(Eq, PartialEq, Debug)]
enum Result<T, E> {
    Ok<T>,
    Err<E>,
}

Clone

#[derive(Clone)]
struct Foo {
    x: i32,
}

#[derive(Clone)]
struct Bar {
    x: Foo,
}

核心 trait

  • Clone, Copy
  • Debug
  • Default
  • Eq, PartialEq
  • Hash
  • Ord, PartialOrd

关联类型

  • 图 graph
  • 节点集 node
  • 边集 edge
trait Graph<N, E> {
    fn edges(&self, n: &N) -> Vec<E>;
}

// 求图中两个节点的距离
fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 {
    1
}

改进版

trait Graph {
    type N;
    type E;
    fn edges(&self, n: &Self::N) -> Vec<Self::E>;
}

struct MyGraph {}
struct MyNode {}
struct MyEdge {}

impl Graph for MyGraph {
    type N = MyNode;
    type E = MyEdge;
    fn edges(&self, n: &MyNode) -> Vec<MyEdge> {
      vec![]
    }
}

关联类型

  • struct MyGraph {}
  • struct MyNode {}
  • struct MyEdge {}

Trait 作用域

i32 实现 Foo trait

trait Foo {
    fn bar(&self) -> bool;
}

impl Foo for i32 {
    fn bar(&self) -> bool {
        true
    }
}

println!("{}", (-123i32).bar());
true

实现 Point 的 Display

use std::fmt::{self, Display};
struct Point {
    x: i32,
    y: i32,
}

impl Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pt({},{})", self.x, self.y)
    }
}

let p0 = Point { x: 0, y: 0 };
println!("{}", p0);       // Display
// println!("{:?}", p0); // Debug
Pt(0,0)

Trait 对象

Trait 对象作为函数参数

trait Draw {
    fn draw(&self) -> String;
}

impl Draw for u32 {
    fn draw(&self) -> String {
        format!("u32: {}", self)
    }
}

impl Draw for i32 {
    fn draw(&self) -> String {
        format!("i32: {}", self)
    }
}

fn draw1(x: &dyn Draw) {
    x.draw();
}

fn draw2(x: Box<dyn Draw>) {
    x.draw();
}

fn main() {
    let a = 10i32;
    let b = 11u32;

    draw1(&a);
    draw1(&b);
    draw2(Box::new(a));
    draw2(Box::new(b));
}

静态分配

trait Foo { fn bar(&self); }

impl Foo for String {
    fn bar(&self) {
        println!("String[{}]", self);
    }
}

impl Foo for i32 {
    fn bar(&self) {
        println!("i32[{}]", self);
    }
}

fn blah<T>(x: T) where T: Foo {
    x.bar()
}

let s = "xxx".to_string();
let i = 12;
blah(s);
blah(i);
String[xxx]
i32[12]

动态分配

trait Foo { fn bar(&self); }

impl Foo for char {
    fn bar(&self) {
        println!("char[{}]", self);
    }
}

impl Foo for i32 {
    fn bar(&self) {
        println!("i32[{}]", self);
    }
}

fn use_foo(f: &dyn Foo) {
    match *f {  // 编译时出错: error[E0308]: mismatched types
        198 => println!("198 aaa"),
        'c' => println!("See?"),
        _ => println!("Something else..."),
    }
}

use_foo(&'c'); // 这里发生强制转换,抹除了类型信息
use_foo(&198i32);
error: Could not compile `cargo45Rxl1`.