如何在safe-Rust中为未调整大小的类型及其拥有的对应类型(如'str'和'String')创建新类型?

如何在safe-Rust中为未调整大小的类型及其拥有的对应类型(如'str'和'String')创建新类型?,rust,newtype,Rust,Newtype,我想创建一对新类型Tag(str)和TagBuf(String), 类似于Path和PathBufwrapOsStr和OsString的方式。我的 最终目标是拥有一个由TagBuf键控的地图,并能够索引到 它只需要一个标签: fn main(){ 让mut m:HashMap=HashMap::new(); m、 插入(TagBuf(“x.”到字符串()),1); assert_eq!(m.get(Tag::new(“x”)),Some(&1)); } 但是我遇到了一些问题,因为标签的大小是动

我想创建一对新类型
Tag(str)
TagBuf(String)
, 类似于
Path
PathBuf
wrap
OsStr
OsString
的方式。我的 最终目标是拥有一个由
TagBuf
键控的地图,并能够索引到 它只需要一个
标签

fn main(){
让mut m:HashMap=HashMap::new();
m、 插入(TagBuf(“x.”到字符串()),1);
assert_eq!(m.get(Tag::new(“x”)),Some(&1));
}
但是我遇到了一些问题,因为
标签的大小是动态的

具体来说,

pub结构标记(str);
pub结构TagBuf(字符串);
impl std::借入::用于TagBuf的借入{
fn借用(&self)->标记(&T){
设s:&str=self.0.as_str();
//如何将“&str”转换为“&Tag”?天真的尝试失败:
&标签(*s)
}
}
error[E0277]:编译时无法知道'str'类型的值的大小
-->src/lib.rs:8:10
|
8 |&标记(*s)
|^^^在编译时没有已知的大小
|
=帮助:没有为'str'实现特征'Sized'`
=注意:所有函数参数必须具有静态已知的大小
我可以使用
#[repr(透明)]
注释,但我希望避免不安全 代码

我已经查看了
Path
/
PathBuf
的源代码,并且

使用标准::借用::借用;
使用std::ops::Deref;
#[报告(透明)]
#[派生(调试、PartialEq、Eq、PartialOrd、Ord、散列)]
pub结构标签(str);
#[派生(调试、PartialEq、Eq、PartialOrd、Ord、哈希、克隆)]
pub结构TagBuf(字符串);
impl标签{
fn新建(s:&s)->标记(&T){
不安全{&*(s.as_ref()as*const str as*const Tag)}
}
}
TagBuf的impl Deref{
类型目标=标签;
fn deref(&self)->标记(&T){
标记::新建(&self.0)
}
}
TagBuf的impl借用{
fn借用(&self)->标记(&T){
self.deref()
}
}
impl为标记打开{
拥有的类型=TagBuf;
fn至_自有(和自有)->TagBuf{
TagBuf(self.0.to_owned())
}
}
fn main(){
让mut m=std::collections::HashMap:::new();
m、 插入(TagBuf(“x.”到字符串()),1);
assert_eq!(m.get(Tag::new(“x”)),Some(&1));
}
…这很有效,我能理解(很好!),但它仍然使用
不安全
,我想避免

我看到了 不使用
不安全的
,但不调整大小的强制似乎很复杂,而且 我不知道如何将它从
[u8]
调整为
str
,因为没有 与
[u8;N]
的严格对应

我还阅读了
Rc
的实现,它似乎做了更多的工作 通过
Rc
进行不安全的转换 我很难理解

我读过一些相关的问题,比如:

……但我还没有找到答案

最近的稳定锈菌是否有办法为
str
安全代码中的
字符串
?如果没有,是否存在RFC或跟踪问题
这是我应该遵循的吗?

如果没有一些小的开销,就无法在安全生锈中解决这一问题

这就是我如何使用
不安全
解决它的:

使用std:{borrow::borrow,ops::Deref};
#[报告(透明)]
#[派生(调试、PartialEq、Eq、PartialOrd、Ord、散列)]
pub结构标签(str);
#[派生(调试、PartialEq、Eq、PartialOrd、Ord、哈希、克隆)]
pub结构TagBuf(字符串);
impl标签{
fn新建(s:&s)->标记(&T){
不安全{&*(s.as_ref()as*const str as*const Tag)}
}
}
TagBuf的impl Deref{
类型目标=标签;
fn deref(&self)->标记(&T){
标记::新建(&self.0)
}
}
TagBuf的impl借用{
fn借用(&self)->标记(&T){
self.deref()
}
}
impl为标记打开{
拥有的类型=TagBuf;
fn至_自有(和自有)->TagBuf{
TagBuf(self.0.to_owned())
}
}
使用std::collections::HashMap;
fn main(){
让mut m=HashMap::new();
m、 插入(TagBuf(“x.”到字符串()),1);
assert_eq!(m.get(Tag::new(“x”)),Some(&1));
}
另见:


我不确定您是否可以直接包装
str
&str
是更常见的形式,可能是因为这个原因。好吧,你现在确实需要使用
unsafe
(或者使用
unsafe
的板条箱)来做这件事。是的,我也很好奇你为什么用
标记(str)
而不是
Tag@PitaJ:这是一个公平的问题,但您将如何实现
Borrow
Path::new()
使用的是不安全的,所以可能需要。谢谢你的第二双眼睛!很高兴看到我的代码与您的代码完全相同。:-)我会接受这一点,但如果在安全的情况下可能的话,我很乐意接受另一个答案。