【问题标题】:How can an IpAddr be converted to an IPv4Addr?如何将 IpAddr 转换为 IPv4Addr?
【发布时间】:2018-08-04 01:55:45
【问题描述】:

在 Rust 中,很容易从 IpV4Addr 创建一个 IpAddr

let ipv4 = IpV4Addr::new(127,0,0,1);
let ip = IpAddr::V4(ipv4);

但似乎没有退路了:

if ip.is_ipv4() {
    let ipv4: IpV4Addr = .....?
}

原因是我需要在某个时候访问 IPv4 地址的八位字节(通过IPv4::octets)以通过网络传输它们。但是,我想在应用程序的其他部分使用更通用的 IpAddr 表示,因为我想在未来实现 IPv6,因此使网络代码不是 IPv4 特定的。

【问题讨论】:

  • 我推荐阅读The Rust Programming Language以熟悉Rust中的基本概念,例如enums
  • 我确实读过它(+ 第 1 版),但我无法将这样的理论信息应用于现实世界的问题;这只是我个人的弱点(我通常需要一个实际的例子来“得到”一些东西)。如果您觉得这样的问题不适合 SO,我将不再发布它们。
  • 我不认为这样的问题是不合适的,只是我觉得他们已经被书回答了。

标签: rust


【解决方案1】:

IpAddr 是 IP 地址的抽象。它是一个枚举,包含 Ipv4AddrIpv6Addr 以及一些提供对两者的抽象访问的方法。

Rust 不允许您将 IpAddr 转换为 Ipv4Addr,因为如果它实际上是 Ipv6Addr 怎么办?你也必须处理这种情况。你让 Rust 相信你已经用match 处理了所有的可能性。

use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

fn main() {
    let ips = [
        IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
        IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)),
    ];

    for ip in ips.iter() {
        match *ip {
            IpAddr::V4(ip4) => println!("ipv4: {}, octets: {:?}", ip4, ip4.octets()),
            IpAddr::V6(ip6) => println!("ipv6: {}, segments: {:?}", ip6, ip6.segments()),
        }
    }
}

不需要默认情况,因为 Rust 类型检查器知道没有其他可能性。 ipsIpAddr 的数组,它只包含两种可能性,V4 或 V6。事实上,如果你在其中放置一个,Rust 会发出警告,所以如果 IpAddr 将来发生变化,你会意识到编译错误。

【讨论】:

    【解决方案2】:

    IpAddr 是一个枚举,所以你可以使用模式匹配:

    if let IpAddr::V4(ipv4) = ip {
        // here ipv4 is of type IpV4Addr
    }
    
    // or, if you need to handle IPv6 as well
    
    match ip {
        IpAddr::V4(ipv4) => { /* handle IPv4 */ }
        IpAddr::V6(ipv6) => { /* handle IPv6 */ }
    }
    

    另外,IpAddrCopy,因此您甚至不必担心会消耗其原始值(ip 变量),它只会为您隐式复制。

    【讨论】:

    • 感谢您的回答!我希望你不介意我接受了 Schwern 的回答(只是因为它更详细一点)。
    猜你喜欢
    • 2014-05-11
    • 1970-01-01
    • 2022-12-20
    • 1970-01-01
    • 1970-01-01
    • 2014-01-17
    • 2010-09-08
    • 2013-09-21
    • 2011-05-14
    相关资源
    最近更新 更多