三种调用方式解释

  在本节里,通过两个模块mod_baremod_trait实现及其三种调用方式比较,详细说明衔接关键词trait作用。

学习内容

  • 理解衔接关键词trait的重要性
  • 掌握衔接关键词trait实现的应用方法

篇目

image

基于结构类型的实现:使用实例调用

  从上面图示,可以了解到下面程序文件直接访问模块mod_bare,该模块是基于结构类型的实现,不存在衔接特质。

// File: examples/bare_hello.rs
use mod_trait_exerci::mod_bare::StructType;
use mod_trait_exerci::mod_bare::TupleType;

fn get_data_from_struct(instances: [StructType; 2]) {
    let data = instances[0].get_tuple();
    assert_eq!(0, data);
    assert_eq!((0), data);
    assert_eq!(instances[0], instances[1]);
    println!("{:?}", instances[0]);
    println!("{:?}", instances[1]);
}

fn get_data_from_tuple(instances: [TupleType; 2]) {
    let data = instances[0].get_tuple();
    assert_eq!(0, data);
    assert_eq!((0), data);
    assert_eq!(instances[0], instances[1]);
    println!("{:?}", instances[0]);
    println!("{:?}", instances[1]);
}

// clear && cargo run --example bare_hello
fn main() {
    let instances: [StructType; 2] = [Default::default(), StructType{data:0}];
    get_data_from_struct(instances);

    let instances: [TupleType; 2] = [Default::default(), TupleType(0)];
    get_data_from_tuple(instances);    
}

基于衔接特质的实现:使用实例调用

  从上面图示,下面程序文件也是直接访问模块mod_trait本身,与上面应用实例不同,这里通过衔接特质方式实现代码,从代码的关键词use语句也可以了解到这一点。

  比较上面程序文件bare_hello.rs和下面文件trait_instance_hello.rs的关键词use语句,可以看到,上面程序文件里的关键词use语句访问模块,采用了绝对路径方式,而下面文件既有绝对路径方式,也有相对路径方式。

// File: examples/trait_instance_hello.rs
use mod_trait_exerci::mod_trait;
use mod_trait::TraitCanal;
use mod_trait::StructType;
use mod_trait::TupleType;

fn get_data_from_struct(instances: [StructType; 2]) {
    let data = instances[0].get_tuple();
    assert_eq!(0, data);
    assert_eq!((0), data);
    assert_eq!(instances[0], instances[1]);
    println!("{:?}", instances[0]);
    println!("{:?}", instances[1]);
}

fn get_data_from_tuple(instances: [TupleType; 2]) {
    let data = instances[0].get_tuple();
    assert_eq!(0, data);
    assert_eq!((0), data);
    assert_eq!(instances[0], instances[1]);
    println!("{:?}", instances[0]);
    println!("{:?}", instances[1]);
}

// clear && cargo run --example trait_instance_hello
fn main() {
    let instances: [StructType; 2] = [Default::default(), StructType::new(0)];
    get_data_from_struct(instances);

    let instances: [TupleType; 2] = [Default::default(), TupleType::new(0)];
    get_data_from_tuple(instances);    
}

基于衔接特质的模块

  从上面图示,可以了解到,下面程序文件也是一个模块mod_where_fn,该模块应用了模块mod_trait的功能,注意该文件关键词use语句只使用了衔接特质TraitCanal,这也是一种访问其父模块的相对路径方式。它的存在意义是什么?这是为用户提供更加灵活的实现而设计的。这里提供了怎么样使用模块,而不必用户完成实现。

  下面代码的方法是一种泛型方法的表达方式,其概念参考下面说明。

  下面将会说明关键词where。在文件mod_where_fn.rs里的两个函数是两个完全相同的实现,只是语法表达方式不同而已。

// File: src/mod_where_fn.rs
use super::mod_trait::TraitCanal;

pub fn get_static_type_ref<Type: TraitCanal>(typ: &Type) -> (u32) {
    typ.get_tuple()
}

pub fn get_static_type_ref_with_where<Type>(typ: &Type) -> (u32)
    where Type: TraitCanal {
    typ.get_tuple()
}

基于衔接特质的实现:作为参数调用

  从上面图示,可以了解到下面程序文件并不是直接访问模块mod_trait本身,而是访问中间模块mod_where_fn完成的,这是一种更加方便和灵活的三层程序设计结构。与模块mod_trait不同,它实现的功能更多的是数据操作功能,这里称之为“数据模块”,而这种中间模块mod_where_fn,它提供更多样化的有实际意义知识性功能,这里称之为“知识模块”。

  无论是什么类型结构,为了获取不同的结构类型属性,都不需要访问其属性名称。

  在使用模块mod_where_fn的函数时,结构类型的实例是作为参数传递给该模块的函数。我们仅仅告诉它我们是‘谁’,我们需要做什么。

  模块mod_trait告诉我们是什么功能,这好比是产品生产原料。模块mod_where_fn解决了怎么做问题,这好比是为用户预先打造的特定产品,当然用户也可以自己制造自己需要的产品。这里程序文件说明了要做什么事情,这好比作为用户使用现成的产品。

// File: examples/trait_where_hello.rs
use mod_trait_exerci::mod_where_fn;
use mod_trait_exerci::mod_trait;
use mod_trait::StructType;
use mod_trait::TupleType;

fn static_struct_ref_with_where(instance: &StructType) {
    let data = mod_where_fn::get_static_type_ref_with_where(instance);
    assert_eq!(0, data);
    assert_eq!((0), data);
}

fn static_tuple_ref_with_where(instance: &TupleType) {
    let data = mod_where_fn::get_static_type_ref_with_where(instance);
    assert_eq!(0, data);
    assert_eq!((0), data);
}

// clear && cargo run --example trait_where_hello
fn main() {
    let instance: StructType = Default::default();
    static_struct_ref_with_where(&instance);

    let instance: TupleType = Default::default();
    static_tuple_ref_with_where(&instance);
}

题外话

浅说面向对象编程、命令式编程和声明式编程

  面向对象编程回答了是什么,命令式编程回答了怎么做,而声明式编程回答了做什么。

数据类型数组

  在Rust语言里,数组是一种基本数据类型。

泛型函数与方法

  在类型理论中,泛型称之为参数多态(parametric polymorphism),对于给定参数(parametric)能够有多种形式(poly是多,morph是形态)的函数或类型。

  在Rust语言里,泛型是一种非常广泛采用的技术,不仅应用函数与方法关键词fn,也应用衔接特质关键词trait等等。其目的是,减少代码重复。

类型范围关键词where

  关键词where用于向泛型类型添加约束,并为编译器提供解决问题所需的信息!

参考资料