gpt4 book ai didi

rust - 如何在安全的 Rust 中为非大小类型及其拥有的对应物(如 `str` 和 `String` )创建新类型?

转载 作者:行者123 更新时间:2023-12-03 11:24:21 26 4
gpt4 key购买 nike

我想创建一对新类型 Tag(str)TagBuf(String) ,
类似于 PathPathBuf包装OsStrOsString .我的
最终目标是拥有一张由 TagBuf 键控的 map 并且能够索引到
只需一个 Tag :

fn main() {
let mut m: HashMap<TagBuf, i32> = HashMap::new();
m.insert(TagBuf("x".to_string()), 1);
assert_eq!(m.get(Tag::new("x")), Some(&1));
}
但是我遇到了问题,因为 Tag是动态大小的。
具体来说, implementing Borrow<Tag> for TagBuf is tricky:
pub struct Tag(str);
pub struct TagBuf(String);

impl std::borrow::Borrow<Tag> for TagBuf {
fn borrow(&self) -> &Tag {
let s: &str = self.0.as_str();
// How can I turn `&str` into `&Tag`? A naive attempt fails:
&Tag(*s)
}
}
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> src/lib.rs:8:10
|
8 | &Tag(*s)
| ^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
= note: all function arguments must have a statically known size
我可以回 unsafe { std::mem::transmute(s) }#[repr(transparent)]注释,但我想避免不安全
代码。
我查看了 Path 的来源/ PathBufcome up with thefollowing:
use std::borrow::Borrow;
use std::ops::Deref;

#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Tag(str);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct TagBuf(String);

impl Tag {
fn new<S: AsRef<str> + ?Sized>(s: &S) -> &Tag {
unsafe { &*(s.as_ref() as *const str as *const Tag) }
}
}

impl Deref for TagBuf {
type Target = Tag;
fn deref(&self) -> &Tag {
Tag::new(&self.0)
}
}

impl Borrow<Tag> for TagBuf {
fn borrow(&self) -> &Tag {
self.deref()
}
}

impl ToOwned for Tag {
type Owned = TagBuf;
fn to_owned(&self) -> TagBuf {
TagBuf(self.0.to_owned())
}
}

fn main() {
let mut m = std::collections::HashMap::<TagBuf, i32>::new();
m.insert(TagBuf("x".to_string()), 1);
assert_eq!(m.get(Tag::new("x")), Some(&1));
}
......这有效,我可以理解(很好!),但它仍然使用 unsafe对于那个 Actor ,我想避免。
我看到了 the Rustonomicon section on exotically sized types , 哪一个
不使用 unsafe ,但是 unsizing 强制看起来很复杂,并且
我从 [u8] 看不到如何适应它至 str ,因为没有
[u8; N] 对应的细丝.
我还阅读了 Rc<str> 的实现,这似乎做了更多
通过 Rc<[u8]> 进行不安全的转换和一些专精魔法
我很难理解。
我已经阅读了一些相关的问题,例如:
  • Implementing FromStr for a custom &[u8] type
  • https://users.rust-lang.org/t/how-to-newtype-string/5211

  • ……但我还没有找到答案。
    最新的稳定版 Rust 是否有办法为 str 定义新类型对?
    String在安全代码中?如果没有,是否有 RFC 或跟踪问题
    我应该遵循?

    最佳答案

    如果没有一些小的开销,这无法在安全的 Rust 中解决。
    这就是我使用 unsafe 解决它的方法:

    use std::{borrow::Borrow, ops::Deref};

    #[repr(transparent)]
    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Tag(str);

    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
    pub struct TagBuf(String);

    impl Tag {
    fn new<S: AsRef<str> + ?Sized>(s: &S) -> &Tag {
    unsafe { &*(s.as_ref() as *const str as *const Tag) }
    }
    }

    impl Deref for TagBuf {
    type Target = Tag;

    fn deref(&self) -> &Tag {
    Tag::new(&self.0)
    }
    }

    impl Borrow<Tag> for TagBuf {
    fn borrow(&self) -> &Tag {
    self.deref()
    }
    }

    impl ToOwned for Tag {
    type Owned = TagBuf;

    fn to_owned(&self) -> TagBuf {
    TagBuf(self.0.to_owned())
    }
    }

    use std::collections::HashMap;

    fn main() {
    let mut m = HashMap::new();
    m.insert(TagBuf("x".to_string()), 1);
    assert_eq!(m.get(Tag::new("x")), Some(&1));
    }
    也可以看看:
  • How do I handle an FFI unsized type that could be owned or borrowed?
  • How to wrap a borrowed value in a newtype that is also a borrowed value?
  • How to avoid temporary allocations when using a complex key for a HashMap?
  • How to implement HashMap with two keys?
  • 关于rust - 如何在安全的 Rust 中为非大小类型及其拥有的对应物(如 `str` 和 `String` )创建新类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64977525/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com