Rust 当输出值不是类型的一部分时,如何实现std::ops::Index
我正在尝试实现一种ip地址类型,它基本上包装了Rust 当输出值不是类型的一部分时,如何实现std::ops::Index,rust,operator-overloading,lifetime,traits,Rust,Operator Overloading,Lifetime,Traits,我正在尝试实现一种ip地址类型,它基本上包装了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
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,
}
}
}
但是,当然,我不能返回对一个一旦函数返回就不存在的值的引用
在这种情况下,有没有办法实现
std::ops::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);
}
使用std::ops;
#[派生(复制、克隆、PartialEq、Eq、PartialOrd、Ord、散列)]
发布结构地址(u32);
枚举字节{
A.
B
C
D
}
impl ops::地址的索引{
类型输出=u8;
#[cfg(target_endian=“big”)]
fn索引和'a u8{
使用std::mem;
let bytes=unsafe{mem::transmute::(&self.0)};
匹配字节{
字节::A=>&字节[0],
字节::B=>&字节[1],
字节::C=>&字节[2],
字节::D=>&字节[3],
}
}
#[cfg(target_endian=“little”)]
fn索引和'a u8{
使用std::mem;
let bytes=unsafe{mem::transmute::(&self.0)};
匹配字节{
字节::A=>&字节[3],
字节::B=>&字节[2],
字节::C=>&字节[1],
字节::D=>&字节[0],
}
}
}
fn main(){
断言(地址(0x12345678)[字节::A],0x12];
}
我的意思是,除了为了混淆语法而不必要地使用不安全的;为地址编制索引和为整数编制索引一样有意义:很少。非常感谢您解释为什么这样做是错误的,并回答了这个问题。我保证我不会实现索引
!冒着丢失某些明显内容的风险,已经存在一个封装适当底层类型的方法。@Shepmaster,是的,但我想在流量生成工具中使用它,因此我希望(至少)实现+
,&
,
和
操作符。恐怕我无法在Ipv4Addr
上轻松实现这一点,因为我无法直接访问底层类型。
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);
}