I want to filter out the IPv4 localhost address by using the constant net::Ipv4Addr::LOCALHOST
when pattern matching:
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(())
}
I get an error
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
does have implementation for PartialEq
and Eq
, so what does that error mean? How do I solve it?
As the error message states:
must be annotated with
#[derive(PartialEq, Eq)]
This is not true for Ipv4Addr
, which implements it manually, instead of deriving it.
Instead, use a match guard:
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(())
}
You may also consider introducing some nesting:
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 explains the underlying decisions more:
- Introduce a feature-gated attribute
#[structural_match]
which can be applied to a struct or enumT
to indicate that constants of typeT
can be used within patterns.- Have
#[derive(Eq)]
automatically apply this attribute to the struct or enum that it decorates. Automatically inserted attributes do not require use of feature-gate.- When expanding constants of struct or enum type into equivalent patterns, require that the struct or enum type is decorated with
#[structural_match]
. Constants of builtin types are always expanded.The practical effect of these changes will be to prevent the use of constants in patterns unless the type of those constants is either a built-in type (like
i32
or&str
) or a user-defined constant for whichEq
is derived (not merely implemented).