【问题标题】:Why can't enum variants be inferred in match arms?为什么不能在匹配臂中推断枚举变体?
【发布时间】:2017-07-06 12:15:31
【问题描述】:

这个例子编译失败:

extern crate nix;
use std::os::unix::io::RawFd;

fn func(fd: RawFd, buf: &mut [u8]) -> Result<(), nix::Error> {
    let (size, nix_addr) = nix::sys::socket::recvfrom(
        fd, buf
    )?;

    let addr = match nix_addr {
        //nix::sys::socket::SockAddr::Inet(addr) => addr.to_std(),
        Inet(addr) => addr.to_std(),
        _ => panic!(),
    };

    Ok(())
}

fn main() {}

这个版本的错误是:

error[E0531]: unresolved tuple struct/variant `Inet`
  --> match_arms.rs:14:3
   |
14 |        Inet(addr) => addr.to_std(),
   |        ^^^^

Inet 行替换为注释掉的行可以成功编译。

编译器似乎要求我自己指定枚举类型,我想它知道我在match arm 中指定的变体是合法的。 但是为什么呢?不能推断出枚举吗? 编译器在这里没有足够的信息来意识到nix_addrnix::…::SocketAddr,因此,Inet 是一个有效的变体(并且带有数据) ?

为什么我必须输入整个内容,或者使用use 将名称拖到当前范围内?

我也试过_::Inet,也失败了。

【问题讨论】:

    标签: enums rust type-inference


    【解决方案1】:
    • 但是为什么呢?不能推断枚举吗?

    根据引入枚举命名空间的RFC 390,这种推断被认为是一种黑客攻击,没有它在设计上会更好。来自 RFC 的替代部分:

    我们可以在 1.0 之后通过添加“回退”案例来解决枚举命名空间,如果在该命名空间中没有其他定义会发生冲突,则可以从其“平面”定义位置引用变体。在保持向后兼容性的总体黑客计划中,这并没有那么糟糕,但仍然比完全不用担心回退更糟糕。

    在 RFC 390 之后不考虑推理的官方原因是没有人真正关心到提出更改:

    @sfackler:

    @netvl Java 是一个有趣的案例,因为您只能在 switch 语句中引用“裸”形式的变体(FOO,而不是 MyEnum.FOO)。 Rust 中的情况有点复杂,因为 match 允许比传统的 switch 语句更强大的模式匹配。最接近的类似物可能是将所有相关的东西隐含地视为以模式导入。这似乎与该提案完全正交,它可能应该有自己的 RFC。

    (从那时起没有人为此编写过 RFC。)

    不过,这样的 RFC 通过的可能性很小。毕竟,您只需要在某处添加一行use nix::sys::socket::SockAddr::* 即可使其工作。向语言中添加一个特性需要大量考虑正确的规范和极端情况(例如,当你 use nix::sys::socket::SockAddr::Unix as Inet 时会发生什么),这可能不值得花时间。

    【讨论】:

    • 也许建议使用use nix::sys::socket... 或别名应该放在这个答案的顶部。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 2014-03-21
    相关资源
    最近更新 更多