Rust学习(通过例子学习Rust)(2)

Rust学习(通过例子学习Rust)(2)

九. 函数

使用fn 关键字开头

9.1 方法

方法(method)是依附于对象的函数。这些方法通过关键字 self 来访问对象中的数据和其他。方法在 impl 代码块中定义。

struct Point {
    x: f64,
    y: f64,
}
impl Point {
    //这类方法一般用 constructor
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }
    //
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    fn area(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;
        ((x1 - x2) * (y1 - y2)).abs()
    }
    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;
        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }
    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p1.y += y;
        self.p2.x += x;
        self.p2.y += y;
    }
}

fn main() {
    let rectangle = Rectangle {
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };
    println!("Area: {}", rectangle.area()); //12
                                            // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`
    println!("Perimeter: {}", rectangle.perimeter()); //14

    // 移动矩形
    let mut rectangle = Rectangle {
        p1: Point::origin(),
        p2: Point::new(1.0, 1.0),
    };
    rectangle.translate(1.0, 1.0);
    println!("Area: {}", rectangle.area()); //1
}
9.2 闭包
9.2.1 闭包的定义

Rust 中的闭包(closure),也叫做 lambda 表达式或者 lambda,是一类能够捕获周围作用域中变量的函数

fn main() {
    // 通过闭包和函数实现自增
    //注意结尾没有分号
    fn function(i: u32) -> u32 {
        i + 1
    }
    let fna = |i: u32| -> u32 { i + 1 };
    let fnb = |i| i + 1;
    let i = 1;
    println!("{}", function(i));
    println!("{}", fna(i));
    println!("{}", fnb(i));
    println!("hello world!");
}
9.2.2 闭包的捕获 和作为输入参数

通过引用:&T;
通过可变引用:&mut T;
通过值:T;

Fn:表示捕获方式为通过引用(&T)的闭包
FnMut:表示捕获方式为通过可变引用(&mut T)的闭包
FnOnce:表示捕获方式为通过值(T)的闭包

fn main() {
    use std::mem;
    //Fn()
    let color = String::from("green");
    let p = || println!("{}", color);
    p(); //greem
         //FnMut()
    let mut count = 0;
    let mut inc = || {
        count += 1;
        println!("count: {}", count);
    };
    inc(); //count: 1
    inc(); //count: 2

    let movalbe = Box::new(3);
    let consume = || {
        println!("`movalbe`:{:?}", movalbe);
        mem::drop(movalbe); //move
    };
    consume();
    //error
    //consume();
}
9.2.3 类型匿名
fn main() {
     限定了 fn 类型
    fn apply<F: Fn()>(f: F) {
        f();
    }

    let f = || println!("hello");
    apply(f);
}
9.2.4 输入参数;
fn call_me<F>(f: F)
where
    F: Fn(),
{
    f();
}
fn function() {
    println!("function");
}
fn main() {
    let c = || println!("c");
    call_me(c);
    call_me(function);
}
9.2.5 输出参数

返回闭包的有效特征是:
Fn
FnMut
FnOnce

fn create_fn() -> impl Fn() {
    let text = "Fn".to_owned();
    move || println!("{}", text)
}
fn create_fnmut() -> impl FnMut() {
    let text = "FnMut".to_owned();
    move || println!("{}", text)
}
fn create_fnonce() -> impl FnOnce() {
    let text = "FnOnce".to_owned();
    move || println!("{}", text)
}
fn main() {
    let fn_once = create_fnonce();
    fn_once();
    let mut fn_mut = create_fnmut();
    fn_mut();
    let fn1 = create_fn();
    fn1();
}
9.3 高阶函数

高阶函数是函数式编程的特性,它是指函数可以作为参数传递给另一个函数,或者返回一个函数作为另一个函数的返回值
Rust 提供了高阶函数(Higher Order Function, HOF),指那些输入一个或多个函数,并且/或者产生一个更有用的函数的函数

fn is_odd(n: u32) -> bool {
    n % 2 == 1
}
fn main() {
    let u = 1000;
    let mut acc = 0;
    for n in 0.. {
        let n_squared = n * n;
        if n_squared > u {
            break;
        } else {
            acc += n_squared;
        }
    }
    println!("{}", acc);

    let sum = (0..)
        .map(|n| n * n)
        .take_while(|&n| n < 1000)
        .filter(|&n| is_odd(n))
        .fold(0, |sum, i| sum + i);
    println!("sum = {}", sum);
}
9.4 发散函数 (!)

发散函数(diverging function)绝不会返回。 它们使用 ! 标记,这是一个空类型。

fn foo() -> ! {
    panic!("foo");
}
fn main() {
    foo();//返回空
}
fn main() {
    fn sum_odd_numbers(up_to: u32) -> u32 {
        let mut acc = 0;
        for i in 0..up_to {
            // 注意这个 match 表达式的返回值必须为 u32,
            // 因为 “addition” 变量是这个类型。
            let addition: u32 = match i%2 == 1 {
                // “i” 变量的类型为 u32,这毫无问题。
                true => i,
                // 另一方面,“continue” 表达式不返回 u32,但它仍然没有问题,
                // 因为它永远不会返回,因此不会违反匹配表达式的类型要求。
                false => continue,
            };
            acc += addition;
        }
        acc
    }
    println!("Sum of odd numbers up to 9 (excluding): {}", sum_odd_numbers(9));
}

10. 模块

Rust 提供了一套强大的模块(module)系统,可以将代码按层次分成多个逻辑单元(模块),并管理这些模块之间的可见性(公有(public)或私有(private))。

模块是项(item)的集合,项可以是:函数,结构体,trait,impl 块,甚至其它模块。

10.1 模块的可见性

默认情况下,模块中的项拥有私有的可见性(private visibility),不过可以加上 pub
修饰语来重载这一行为。模块中只有公有的(public)项可以从模块外的作用域访问

10.2 结构体的可见性

结构体的字段也是一个可见性的层次。字段默认拥有私有的可见性,也可以加上 pub 修饰语来重载该行为。只有从结构体被定义的模块之外访问其字段时,这个可见性才会起作用,其意义是隐藏信息(即封装,encapsulation)

mod my {
    #[derive(Debug)]
    pub struct OpenBox<T> {
        pub content: T,
    }

    #[derive(Debug)]
    #[allow(dead_code)]
    pub struct ClosedBox<T> {
        content: T,
    }

    impl<T> ClosedBox<T> {
        pub fn new(content: T) -> Self {
            ClosedBox { content }
        }
    }
}

fn main() {
    let open_box = my::OpenBox { content: 10 };
    let close_box = my::ClosedBox::new(10);
    println!("{:?}", open_box);
    println!("{:?}", close_box);
    println!("{:?}", open_box.content);

    // error field `content` of `CloseBox` is private
    //println!("{:?}", close_box.content);
    // error field `content` of `CloseBox` is private
    //let close_box2 = my::ClosedBox { content: 10 };
}
10.3 use 声明

use 声明可以将一个完整的路径绑定到一个新的名字,从而更容易访问。

10.4 super和self

在模块中,super 关键字表示当前模块的父模块,self 关键字则表示当前模块。

fn function() {
    println!("call funciton");
}
mod cool {
    pub fn function() {
        println!("call cool function");
    }
}

mod my {
    fn funciton() {
        println!("call my function");
    }

    mod cool {
        pub fn function() {
            println!("call cool function");
        }
    }

    pub fn indirect_call() {
        println!("call function start");
        //self
        //slef::function() 和function() 一样
        self::funciton();
        funciton();

        //self::my
        self::cool::function();

        //super::function ·my· 模块同级的function
        super::function();

        //最外层 cool::function
        {
            use crate::cool::function;
            function();
        }
    }
}
10.5 文件分层
$ tree .
.
|-- my
|   |-- inaccessible.rs
|   |-- mod.rs
|   `-- nested.rs
`-- split.rs
//split.rs
mod my;
fn function(){
    println!("call function");
}
fn main() {
    my::funciton();
    function();
    my::indirect_call();
    my::nested::function();
}
//mod.rs
pub mod nested;
mod inaccessible;

pub fn funciton(){
    println!("call funciton");
}
fn private_function(){
    println!("call private function");
}
pub fn indirect_call() {
    println!("call function start");
    private_function();
}
//nested.rs
pub fn function() {
    println!("call nested function");
}
fn private_function(){
    println!("call private function");
}
//inaccessible.rs
pub fn public_function(){
    println!("call public function");
}

十一. create

crate(中文有 “包,包装箱” 之意)是 Rust 的编译单元
编译库
rustc --create-type=lib mylib.rs
使用库
ructs main.rs --extern mylib=library.rlib

十二. cargo

/// 1. 创建一个新项目
cargo new hello
/// 2. 创建一个库
cargo new --lib hello
// 项目目录

foo
├── Cargo.toml
└── src
    ├── main.rs
    └── bin
        └── my_other_bin.rs

/// 3.测试
cargo test

/// 4. 构建
[package]

build = “build.rs”

十三. 属性

/// 1. 属性语法

#[attribute = "value"]
#[attribute(key = "value")]
#[attribute(value)]
#[attribute(value, value2)]

/// 2. 死代码
#[allow(dead_code)]

/// 3. create

/// 4.cfg 宏
cfg 属性:在属性位置中使用 #[cfg(…)]
cfg! 宏:在布尔表达式中使用 cfg!(…)
有部分条件如 target_os 是由 rustc 隐式地提供的,但是自定义条件必须使用 --cfg 标记来传给 rustc。

十四. 范型

泛型的类型参数是使用尖括号和大驼峰命名的名称:<Aaa, Bbb, …> 来指定的。泛型类型参数一般用 来表示。在 Rust 中,“泛型的” 除了表示类型,还表示可以接受一个或多个泛型类型参数 的任何内容。任何用泛型类型参数表示的类型都是泛型,其他的类型都是具体(非泛型)类型。

14.1. 泛型函数

```struct A; // 具体类型 A
struct S(A); // 具体类型 S
struct SGen(T); // 泛型类型 SGen

// 下面全部函数都得到了变量的所有权,并立即使之离开作用域,将变量释放。

// 定义一个函数 reg_fn,接受一个 S 类型的参数 _s
// 因为没有 <T> 这样的泛型类型参数,所以这不是泛型函数。
fn reg_fn(_s: S) {}

// 定义一个函数 gen_spec_t,接受一个 SGen<A> 类型的参数 _s
// SGen<> 显式地接受了类型参数 A,且在 gen_spec_t 中,A 没有被用作
// 泛型类型参数,所以函数不是泛型的。
fn gen_spec_t(_s: SGen) {}

// 定义一个函数 gen_spec_i32,接受一个 SGen<i32> 类型的参数 _s
// SGen<> 显式地接受了类型参量 i32,而 i32 是一个具体类型。
// 由于 i32 不是一个泛型类型,所以这个函数也不是泛型的。
fn gen_spec_i32(_s: SGen) {}

// 定义一个函数 generic,接受一个 SGen<T> 类型的参数 _s
// 因为 SGen<T> 之前有 <T>,所以这个函数是关于 T 的泛型函数。
fn generic(_s: SGen) {}

fn main() {
// 使用非泛型函数
reg_fn(S(A)); // 具体类型。
gen_spec_t(SGen(A)); // 隐式地指定类型参数 A
gen_spec_i32(SGen(6)); // 隐式地指定类型参数 i32

// 为 `generic()` 显式地指定类型参数 `char`。
generic::<char>(SGen('a'));

// 为 `generic()` 隐式地指定类型参数 `char`。
generic(SGen('c'));

}


#### 14.2. 泛型实现

struct Val {
val: f64
}

struct GenVal{
gen_val: T
}

// Val 的 impl
impl Val {
fn value(&self) -> &f64 { &self.val }
}

// GenVal 的 impl,指定 T 是泛型类型
impl GenVal {
fn value(&self) -> &T { &self.gen_val }
}

fn main() {
let x = Val { val: 3.0 };
let y = GenVal { gen_val: 3i32 };

println!("{}, {}", x.value(), y.value());

}


#### 14.3. trait
当然 trait 也可以是泛型的

#### 14.4. 泛型约束
在使用泛型时,类型参数常常必须使用 trait 作为约束(bound)来明确规定类型应实现哪些功能

#### 14.5. 多从约束
多重约束(multiple bounds)可以用 + 连接。和平常一样,类型之间使用 , 隔开。

use std::fmt::{Debug, Display};

fn compare_prints<T: Debug + Display>(t: &T) {
println!(“Debug: {:?}”, t);
println!(“Display: {}”, t);
}

fn compare_types<T: Debug, U: Debug>(t: &T, u: &U) {
println!(“t: {:?}”, t);
println!(“u: {:?}”, u);
}

fn main() {
let string = “words”;
let array = [1, 2, 3];
let vec = vec![1, 2, 3];

compare_prints(&string);
//compare_prints(&array);
// 试一试 ^ 将此行注释去掉。

compare_types(&array, &vec);

}

#### 14.6 where 子句
约束也可以使用 where 分句来表达,它放在 { 的前面,而不需写在类型第一次出现之前。另外 where 从句可以用于任意类型的限定,而不局限于类型参数本身。
impl <A: TraitB + TraitC, D: TraitE + TraitF> MyTrait<A, D> for YourType {}
// 使用 `where` 从句来表达约束
impl <A, D> MyTrait<A, D> for YourType where
    A: TraitB + TraitC,
    D: TraitE + TraitF {}

#### 14.7 newtype 
定义字段机构
#### 14.8 关联项
关联项”(associated item)指与多种类型的项有关的一组规则。它是 trait 泛型的扩展,允许在 trait 内部定义新的项。

struct Container(i32, i32);

trait Contans {
// 在这里定义可以被方法使用的泛型类型。
type A;
type B;
fn contains(&self, a: &Self::A, b: &Self::B) -> bool;
fn first(&self) -> i32;
fn second(&self) -> i32;
}

impl Contans for Container {
//指出类型 实现泛型类型
type A = i32;
type B = i32;
fn contains(&self, a: &Self::A, b: &Self::B) -> bool {
a == b
}

fn first(&self) -> Self::A {
    self.0
}
fn second(&self) -> Self::B {
    self.1
}

}

fn difference(container: Container) -> i32 {
container.first() - container.second()
}

fn main() {
let numbrer1 = 2;
let numbber2 = 10;
let container = Container(numbrer1, numbber2);
println!(“{}”, difference(container));
}


#### 14.9 虚类型参数
虚类型(phantom type)参数是一种在运行时不出现,而在(且仅在)编译时进行静态检查的类型参数。
#[derive(PartialEq)] // 允许这种类型进行相等测试。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值