Почему я не могу использовать константу при сопоставлении с образцом, хотя он реализует PartialEq и Eq? - PullRequest
2 голосов
/ 11 марта 2019

Я хочу отфильтровать адрес локального хоста IPv4, используя константу net::Ipv4Addr::LOCALHOST при сопоставлении с шаблоном:

use get_if_addrs; // 0.5.3
use std::net;

fn main() -> std::io::Result<()> {
    assert_eq!(
        "127.0.0.1".parse::<net::Ipv4Addr>().unwrap(),
        net::Ipv4Addr::LOCALHOST
    );
    {
        let ifaces = get_if_addrs::get_if_addrs().unwrap();
        for iface in ifaces {
            match iface.addr {
                get_if_addrs::IfAddr::V4(get_if_addrs::Ifv4Addr {
                    ip: _,
                    netmask: _,
                    broadcast: None,
                }) => (),
                get_if_addrs::IfAddr::V4(get_if_addrs::Ifv4Addr {
                    ip: net::Ipv4Addr::LOCALHOST,
                    netmask: _,
                    broadcast: _,
                }) => (),
                get_if_addrs::IfAddr::V4(addr) => println!("{:?}", addr),
                get_if_addrs::IfAddr::V6(_) => (),
            }
        }
    }
    Ok(())
}

Я получаю ошибку

error: to use a constant of type `std::net::Ipv4Addr` in a pattern, `std::net::Ipv4Addr` must be annotated with `#[derive(PartialEq, Eq)]`
  --> src/main.rs:19:25
   |
19 |                     ip: net::Ipv4Addr::LOCALHOST,
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^

warning: unreachable pattern
  --> src/main.rs:23:17
   |
23 |                 get_if_addrs::IfAddr::V4(addr) => println!("{:?}", addr),
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: #[warn(unreachable_patterns)] on by default

std::net::Ipv4Addr имеет реализацию для PartialEq и Eq, так что означает эта ошибка? Как мне это решить?

1 Ответ

4 голосов
/ 11 марта 2019

Поскольку сообщение об ошибке гласит:

должно быть аннотировано #[derive(PartialEq, Eq)]

Это не верно для Ipv4Addr, чтореализует это вручную, а не выводит его.

Вместо этого используйте матч-охранник :

use get_if_addrs; // 0.5.3

fn main() -> std::io::Result<()> {
    let ifaces = get_if_addrs::get_if_addrs().unwrap();
    for iface in ifaces {
        match iface.addr {
            get_if_addrs::IfAddr::V4(get_if_addrs::Ifv4Addr {
                broadcast: None, ..
            }) => (),
            get_if_addrs::IfAddr::V4(get_if_addrs::Ifv4Addr { ip, .. }) if ip.is_loopback() => (),
            get_if_addrs::IfAddr::V4(addr) => println!("{:?}", addr),
            get_if_addrs::IfAddr::V6(_) => (),
        }
    }

    Ok(())
}

Вы также можете рассмотреть возможность введения некоторых вложений:

use get_if_addrs::{IfAddr, Ifv4Addr}; // 0.5.3

fn main() -> std::io::Result<()> {
    let ifaces = get_if_addrs::get_if_addrs().unwrap();
    for iface in ifaces {
        match iface.addr {
            IfAddr::V4(addr) => match addr {
                Ifv4Addr {
                    broadcast: None, ..
                } => (),
                Ifv4Addr { ip, .. } if ip.is_loopback() => (),
                addr => println!("{:?}", addr),
            },
            IfAddr::V6(_) => (),
        }
    }

    Ok(())
}

RFC 1445 объясняет лежащие в основе решения более подробно:

  • Ввести атрибут gated #[structural_match], который можно применять к структуре или перечислению T, чтобы указать, что константытип T может использоваться в шаблонах.
  • У #[derive(Eq)] автоматически применяется этот атрибут к деку или структуре, которую он декорирует.Автоматически вставляемые атрибуты не требуют использования feature-gate.
  • При расширении констант типа struct или enum в эквивалентные шаблоны требуется, чтобы тип struct или enum был украшен #[structural_match].Константы встроенных типов всегда расширяются.

Практическим эффектом этих изменений будет предотвращение использования констант в шаблонах, если только тип этих констант не является встроенным (например, * 1040).* или &str) или пользовательская константа, для которой Eq является производным (не просто реализовано ).

...