TypeId 컨텐츠 체크 아웃

9870 단어 Rusthashtech
Rust의 표준 라이브러리에는 고유한 ID로 사용할 수 있는 유형std::any::TypeId이 있습니다.std::cmp::Eq,std::cmp::Ord,std::hash::Hash 등을 실시했기 때문에 그렇게 사전의 열쇠로 삼는 것은 가능하지만 이 보도에서 우리는 그 내용(강제적이지만 안전히)을 꺼내는 것을 고려했다.
주의점은 이 글의 내용이 TypeId의 내부 실시에 의존하면 장래TypeId의 내부 구조가 변경될 때 행동이 이상해질 수 있다는 것이다.

내부 상태가 필요한 이유


표준고TypeId를 보면 이런 구조입니다.
pub struct TypeId {
    t: u64,
}
여기tpub 등이 있다면[1] 말이 빠르지만 아쉽게도 이것t이 숨겨져 있다.
숨겨진 이상 Rust 개발자들은 내부 상태를 직접 이용하는 것을 고려하지 않고 이런 기사를 썼는데 나도 기본적으로 직접 사용해서는 안 된다.
그래도 내부 상태를 원하는 경우가 있어요.
  • 삼각목의 열쇠로 사용
  • FFI 및 직렬 통신 시 사용
  • 이런 패턴.
    삼각목은 연상 배열로 사용할 수 있는 데이터 구조이지만 반드시 열쇠를 바이트열로 사용해야 한다.
    예를 들어qp_trie 이런 기중기는 삼각목의 일종인 QP-trie를 실현했지만 열쇠를 요구하는 것은Borrow<[u8]>이다.
    따라서 TypeId 상태를 유지하면 키로 처리할 수 없지만 내부 상태를 꺼내면 키로 처리할 수 있다.
    FFI와 통신에 사용되는 경우에도 예컨대(Vec<TypeId>, std::collections::HashMap<TypeId, usize>)와 같은 구조를 준비하지 않고 출입구에서 이런 손을 물어뜯는 것은 아니다.
    그러나 단순히 유일한 ID로서 단시간(저장한 뒤 다시 읽는 등 하지 않음) 활용이라면 그렇게 내부 상태를 사용해도 문제가 없을 것이고, 전환 비용도 필요 없을 것이다.
    '시목 대신 해시맵을 쓰면 된다','큰 비용이 아니기 때문에 씹는 전환이 좋다'는 판단도 나쁘지 않을 것이다.대부분의 경우 그만하면 충분하겠지.필자가 단지 연기의 명수일 뿐이라면, 그것은.

    std:hash:Hasher 설치


    실제로 무엇을 해야 하는지TypeId 남용 실시Hash.
    실시Hasher의 유형, Hash::hash()라고 부르면 Hasher::write() 등을 통해 내부 상태로부터의 값을 받아들일 수 있다.
    #[derive(Default)]
    struct TypeIdHasher(u64, u32);
    impl Hasher for TypeIdHasher {
        fn write(&mut self, bytes: &[u8]) {
            for &b in bytes {
                self.0 ^= (b as u64).rotate_left(self.1);
                self.1 = (self.1 + 8) % 64;
            }
        }
        fn write_u64(&mut self, i: u64) {
            self.0 ^= i.rotate_left(self.1);
        }
        fn finish(&self) -> u64 {
            self.0
        }
    }
    
    fn type_id_inner(type_id: &TypeId) -> u64 {
        let mut hasher = TypeIdHasher::default();
        type_id.hash(&mut hasher);
        hasher.finish()
    }
    
    이런 느낌이에요.Hasher는 실현writefinish가 가능하지만 TypeId의 내부 상태는u64이기 때문에 write_u64호칭이 기대된다.
    또 이 시행방식에서 예컨대TypeId의 내부상태가 u128일 경우TypeIdHasher의 내부상태가 부족해 충돌이 발생하는데, write_u64가 아닌 write일 때 대endian의 환경에서는 기존 내부상태와 다른 값[2]을 받을 수 있다.
    같은 방법으로 내부는 비공개이지만 해시가 설치된 유형에서 내부 상태를 꺼낼 수 있다.나는 해야 한다고 말하지 않았다.

    추가:안전하지 않은 방법


    fn type_id_inner(type_id: &TypeId) -> u64 {
        let ptr = type_id as *const TypeId as *const u64;
        unsafe { *ptr }
    }
    
    더 이상은 안 돼.
    각주pub가 있으면 내부 상태가 바뀌어 추가되지 않습니다.예를 들어 Borrow<u64>↩︎도 가능합니다.
    이 점에 관해서는 최소한 정보량이 같고 단순한 유일한 ID로만 이용된다면 문제가 될 수 없다↩︎

    좋은 웹페이지 즐겨찾기