为什么在匹配组中可以推断出枚举变体?

时间:2017-02-17 05:20:23

标签: enums rust type-inference

此示例无法编译:

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臂中指定的变体是合法的。 但为什么呢?无法推断枚举?编译器是否有足够的信息来识别nix_addrnix::…::SocketAddr,因此,Inet是一个有效的变体(和一个有数据的?)

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

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

1 个答案:

答案 0 :(得分:7)

  • 但为什么呢?无法推断枚举?

根据引入枚举命名空间的RFC 390,这个推理被认为是一个黑客,并没有更好的设计。来自RFC的替代部分:

  

我们可以在1.0之后通过添加&#34; fallback&#34;来实现枚举命名空间。需要解决的案例,其变体可以从他们的&#34; flat&#34;定义位置,如果该命名空间中没有其他定义冲突。在保持向后兼容性的黑客计划中,这并不是那么糟糕,但仍然明显比不必担心回退更糟糕。

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

  

@sfackler

     

@netvl Java是一个有趣的案例,你只能参考&#34;裸&#34;中的变体。 FOO语句中的表单(MyEnum.FOO,而不是switch)。 Rust中的情况有点复杂,因为match允许比传统的switch语句更强大的模式匹配。最接近的模拟可能是隐含地处理在模式中导入的所有相关内容。这似乎与此提案足够正确,它可能值得拥有自己的RFC。

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

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