【译】Rust中的Sizedness (六)

290 阅读5分钟

原文链接: https://github.com/pretzelhammer/rust-blog/blob/master/posts/sizedness-in-rust.md

原文标题: Sizedness in Rust

公众号: Rust碎碎念

用户定义的单元结构体(User-Defined Unit Structs)

单元结构体是没有任何字段的结构体,例如:

struct Struct;

单元结构比()更有用的一些属性:

  • 我们可以在自己的单元结构体上实现任何我们想要的trait, Rust的trait孤儿规则阻止我们为()实现trait,因为()被定义在标准库里
  • 在我们程序的上下文环境中,单元结构体可以被赋予有意义名字
  • 单元结构体,像所有的结构体一样,默认是非拷贝(non-Copy)的,这在我们程序上下文环境中可能是重要的

Never Type

第二常见的ZST是never类型:!。它被叫做never类型是因为它表示永远不会产生任何值的计算。

never类型不同于()的一些有趣的属性:

  • !可以被强制转换到任意其他的类型
  • 无法创建一个!的实例

第一个有趣的属性对于对于人体工程学非常有用并且允许我们使用下面这些方便的宏:

// nice for quick prototyping
fn example<T>(t: &[T]) -> Vec<T> {
    unimplemented!() // ! coerced to Vec<T>
}

fn example2() -> i32 {
    // we know this parse call will never fail
    match "123".parse::<i32>() {
        Some(num) => num,
        None => unreachable!(), // ! coerced to i32
    }
}

fn example3(bool: someCondition) -> &'static str {
    if (!someCondition) {
        panic!() // ! coerced to &str
    } else {
        "str"
    }
}

breakcontinue,和return表达式也有!类型:

fn example() -> i32 {
    // we can set the type of x to anything here
    // since the block never evaluates to any value
    let xString = {
        return 123 // ! coerced to String
    };
}

fn example2(nums: &[i32]) -> Vec<i32> {
    let mut filtered = Vec::new();
    for num in nums {
        filtered.push(
            if *num < 0 {
                break // ! coerced to i32
            } else if *num % 2 == 0 {
                *num
            } else {
                continue // ! coerced to i32
            }
        );
    }
    filtered
}

!的第二个有趣的属性让我们能够让我们在类型级别把特定的状态标记为不可能。让我们看看下面的函数:

fn function() -> Result<SuccessError>;

我们知道,如果这个函数返回并且是成功的,Result将会持有Success类型的实例,如果它出错了,Result将会包含Error类型的某个实例。现在让我们和下面这个函数前面对比一下:

fn function() -> Result<Success, !>;

我们知道,如果这个函数返回并且是成功的,Result将会持有Success类型的实例,如果它出错了...等等,它永远不会出错,因为无法创建一个!的实例。通过上面给出的函数签名,我们知道这个函数永远不会出错。那么下面这个函数签名呢:

fn function() -> Result<!, Error>;

和前面的恰好相反:如果这个函数返回,我们知道它一定是出错的,因为成功是不可能的。

前面例子的一个实际应用是StringFromStr实现,因为它在把&str转换到String时是不可能失败的:

#![feature(never_type)]

use std::str::FromStr;

impl FromStr for String {
    type Err = !;
    fn from_str(s: &str-> Result<StringSelf::Err> {
        Ok(String::from(s))
    }
}

后面一个例子的实际应用是一个运行无限循环的函数,这个函数永远不会返回,比如一个响应客户端请求的服务器,除非出现某些错误:

#![feature(never_type)]

fn run_server() -> Result<!, ConnectionError> {
    loop {
        let (request, response) = get_request()?;
        let result = request.process();
        response.send(result);
    }
}

feature标志是必要的,因为never类型存在并工作于Rust内部,在用户代码里使用它被当做是实验性质(experimental)的。

关键点(Key Takeaway)

  • !可以被强制转到到任何其他的类型
  • 无法创建!的实例,我们可以使用这一点在类型级别把一个状态标记为不可能的

本文禁止转载,谢谢配合!欢迎关注我的微信公众号: Rust碎碎念

Rust碎碎念
Rust碎碎念