当输出值不属于类型时如何实现std::ops::Index
How to implement std::ops::Index when the output value is not part of the type
我正在尝试实现一个基本上包含 u32
:
的 IP 地址类型
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(u32);
我正在实施对 IP 地址有意义的 std::ops
运算符(&
、|
、+
、-
等。 ).唯一造成麻烦的是 std::ops::Index
:
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(u32);
enum Byte {
A,
B,
C,
D
}
impl ops::Index<Byte> for Address {
type Output = u8;
fn index<'a>(&'a self, byte: Byte) -> &'a Self::Output {
match byte {
Byte::A => ((self.0 & 0xFF000000) >> 24) as u8,
Byte::B => ((self.0 & 0x00FF0000) >> 16) as u8,
Byte::C => ((self.0 & 0x0000FF00) >> 8) as u8,
Byte::D => (self.0 & 0x000000FF) as u8,
}
}
}
这显然无法编译,因为我无法在需要 &u8
时 return 一个 u8
。修复它的天真尝试是:
impl ops::Index<Byte> for Address {
type Output = u8;
fn index<'a>(&'a self, byte: Byte) -> &'a Self::Output {
match byte {
Byte::A => &(((self.0 & 0xFF000000) >> 24) as u8),
Byte::B => &(((self.0 & 0x00FF0000) >> 16) as u8),
Byte::C => &(((self.0 & 0x0000FF00) >> 8) as u8),
Byte::D => &((self.0 & 0x000000FF) as u8),
}
}
}
但是,当然,一旦函数 returns.
,我就不能 return 对不再存在的值的引用
在这种情况下,我有办法实现 std::ops::Index
吗?在我看来不是这样,但我希望有人能证明我是错的。
好吧,解决这个问题的最简单和最惯用的方法是 不 实现 Index
,而是使用名为 octet
的方法或其他方法. Index
用于索引容器;它根本不兼容动态生成新值。
所以。这就是你的答案。
你绝对不应该不做我关于要描述的任何事情,因为没有充分的理由去做,而且我我写出来只是因为你技术上问是否有任何办法...
您已收到警告。
...八位字节就在那里!除非你编译的机器的字节 不是 8 位,或者具有比 8 位更细粒度的寻址,否则你没有理由不能这样做:
use std::ops;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(u32);
enum Byte {
A,
B,
C,
D
}
impl ops::Index<Byte> for Address {
type Output = u8;
#[cfg(target_endian="big")]
fn index<'a>(&'a self, byte: Byte) -> &'a u8 {
use std::mem;
let bytes = unsafe { mem::transmute::<_, &[u8; 4]>(&self.0) };
match byte {
Byte::A => &bytes[0],
Byte::B => &bytes[1],
Byte::C => &bytes[2],
Byte::D => &bytes[3],
}
}
#[cfg(target_endian="little")]
fn index<'a>(&'a self, byte: Byte) -> &'a u8 {
use std::mem;
let bytes = unsafe { mem::transmute::<_, &[u8; 4]>(&self.0) };
match byte {
Byte::A => &bytes[3],
Byte::B => &bytes[2],
Byte::C => &bytes[1],
Byte::D => &bytes[0],
}
}
}
fn main() {
assert_eq!(Address(0x12345678)[Byte::A], 0x12);
}
我的意思是,除了为了混淆语法而不必要地使用 unsafe
之外;索引一个 地址 和索引一个整数一样有意义:非常少。
我正在尝试实现一个基本上包含 u32
:
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(u32);
我正在实施对 IP 地址有意义的 std::ops
运算符(&
、|
、+
、-
等。 ).唯一造成麻烦的是 std::ops::Index
:
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(u32);
enum Byte {
A,
B,
C,
D
}
impl ops::Index<Byte> for Address {
type Output = u8;
fn index<'a>(&'a self, byte: Byte) -> &'a Self::Output {
match byte {
Byte::A => ((self.0 & 0xFF000000) >> 24) as u8,
Byte::B => ((self.0 & 0x00FF0000) >> 16) as u8,
Byte::C => ((self.0 & 0x0000FF00) >> 8) as u8,
Byte::D => (self.0 & 0x000000FF) as u8,
}
}
}
这显然无法编译,因为我无法在需要 &u8
时 return 一个 u8
。修复它的天真尝试是:
impl ops::Index<Byte> for Address {
type Output = u8;
fn index<'a>(&'a self, byte: Byte) -> &'a Self::Output {
match byte {
Byte::A => &(((self.0 & 0xFF000000) >> 24) as u8),
Byte::B => &(((self.0 & 0x00FF0000) >> 16) as u8),
Byte::C => &(((self.0 & 0x0000FF00) >> 8) as u8),
Byte::D => &((self.0 & 0x000000FF) as u8),
}
}
}
但是,当然,一旦函数 returns.
,我就不能 return 对不再存在的值的引用在这种情况下,我有办法实现 std::ops::Index
吗?在我看来不是这样,但我希望有人能证明我是错的。
好吧,解决这个问题的最简单和最惯用的方法是 不 实现 Index
,而是使用名为 octet
的方法或其他方法. Index
用于索引容器;它根本不兼容动态生成新值。
所以。这就是你的答案。
你绝对不应该不做我关于要描述的任何事情,因为没有充分的理由去做,而且我我写出来只是因为你技术上问是否有任何办法...
您已收到警告。
...八位字节就在那里!除非你编译的机器的字节 不是 8 位,或者具有比 8 位更细粒度的寻址,否则你没有理由不能这样做:
use std::ops;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Address(u32);
enum Byte {
A,
B,
C,
D
}
impl ops::Index<Byte> for Address {
type Output = u8;
#[cfg(target_endian="big")]
fn index<'a>(&'a self, byte: Byte) -> &'a u8 {
use std::mem;
let bytes = unsafe { mem::transmute::<_, &[u8; 4]>(&self.0) };
match byte {
Byte::A => &bytes[0],
Byte::B => &bytes[1],
Byte::C => &bytes[2],
Byte::D => &bytes[3],
}
}
#[cfg(target_endian="little")]
fn index<'a>(&'a self, byte: Byte) -> &'a u8 {
use std::mem;
let bytes = unsafe { mem::transmute::<_, &[u8; 4]>(&self.0) };
match byte {
Byte::A => &bytes[3],
Byte::B => &bytes[2],
Byte::C => &bytes[1],
Byte::D => &bytes[0],
}
}
}
fn main() {
assert_eq!(Address(0x12345678)[Byte::A], 0x12);
}
我的意思是,除了为了混淆语法而不必要地使用 unsafe
之外;索引一个 地址 和索引一个整数一样有意义:非常少。