![](/img/trans.png)
[英]How can I use lifetime bounds to solve “reference must be valid for the static lifetime”
[英]How can I own a string through reference if its lifetime is static?
在Rust中,我想给一个类起一个名字,这个类拥有这个名字。
有时,名称是通过String
传递的。 对于这种情况,我可以简单地移动所有权。
但是有时此名称由静态字符串( &str
)给出。 对于这种情况,我想引用该字符串,而不是从中创建一个String
。
我的问题是:如何在课堂上声明此名称字段? 应该是什么类型?
要求的一些更新/背景:
String
和&str
是我想将动态分配减少到最小。 一种选择是将名称成员声明为可以包含String
或&'static str
的枚举:
enum Name {
Static(&'static str),
Owned(String),
}
struct Class {
name: Name,
// ...
}
然后,该类可以提供适当的构造函数(必须有两个)和用于将名称作为字符串切片访问的get_name()
方法:
impl Class {
pub fn new_from_str(name: &'static str) -> Class {
Class { name: Name::Static(name) }
}
pub fn new_from_owned(name: String) -> Class {
Class { name: Name::Owned(name) }
}
pub fn get_name(&self) -> &str {
match self.name {
Name::Owned(ref s) => s.as_str(),
Name::Static(s) => s,
}
}
}
fn main() {
let c1 = Class::new_from_str("foo");
let c2 = Class::new_from_owned("foo".to_string());
println!("{} {}", c1.get_name(), c2.get_name());
}
另一个选择是为此使用标准库提供的Cow
类型 :
use std::borrow::Cow;
struct Class {
name: Cow<'static, str>,
}
由于Cow
实现了Into
特性,因此现在可以将构造函数编写为单个通用函数:
pub fn new<T>(name: T) -> Class
where T: Into<Cow<'static, str>> {
Class { name: name.into() }
}
Cow
还实现了Deref
特征,允许将get_name()
编写为:
pub fn get_name(&self) -> &str {
return &self.name;
}
在这两种情况下, name
成员将等于较大变体的大小加上鉴别符所占用的空间。 由于String
在这里是较大的类型,并且它占用三个指针大小(字符串内容被单独分配并且不计数),因此Name
总共将占用四个指针大小。 在显式enum
情况下,可以通过将字符串装箱来使成员更小:
enum Name {
Static(&'static str),
Owned(Box<String>),
}
这会将Name
的大小减小为三个指针大小,其中一个插槽用于区分符,其余两个用于字符串切片。 不利之处在于,它需要为所有者字符串的情况进行额外的分配和间接寻址-但如果您的大多数类名都来自静态字符串切片,则它可能仍会奏效。
您可以允许使用多种类型的方法是使用Into
特性。 这是通用的,因为它可以确保类型之间的安全转换。
这样, str
切片可以“转换为”拥有的String
。
一些测试代码来演示它:
#[derive(Debug)]
struct Test {
name: String,
}
impl Test {
pub fn new<T: Into<String>>(t: T) -> Test {
Test { name: t.into() }
}
}
fn main() {
let t = Test::new("a");
println!("{:?}", t);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.