簡體   English   中英

當輸出值不是類型的一部分時,如何實現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被期望時&u8我無法返回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),
        }
    }
}

但是,當然,一旦函數返回,我將無法返回對不再存在的值的引用。

在這種情況下,我有沒有辦法實現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 索引地址和索引整數意義一樣大:很少。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM