Rust 枚举中 str/String 值的最佳实践是什么?

Rbj*_*bjz 5 string enums lifetime rust

我有一个非常赏心悦目的东西,但我担心它的含义:

#[derive(Eq, PartialEq, Debug)]
pub enum SmtpHost {     
    DOMAIN(String),
    IPV4(Ipv4Addr),
    IPV6(Ipv6Addr),
    UNKNOWN { label:String, literal:String },
}
Run Code Online (Sandbox Code Playgroud)

我用 PEG 语法来填充它,&str所以所有的字符串调用看起来都是这样的 -SmtpHost::Domain(s.to_string())

我希望这些枚举成为解析器的结果,例如smtp_parser::host< 'input >(s: 'input & str) -> SmtpHost

我也尝试过 ref 方法,但是很快就开始变得笨拙:

#[derive(Eq, PartialEq, Debug)]
pub enum SmtpHost<'a > {     
    DOMAIN(&'a str),
    IPV4(Ipv4Addr),
    IPV6(Ipv6Addr),
    UNKNOWN { label:&'a str, literal:&'a str },
}
Run Code Online (Sandbox Code Playgroud)

所以我要么/要么……但你更清楚。告诉我:o)

我的学习项目供参考

zst*_*art 5

&str和之间的关键区别String在于所有权。String拥有,但&str借用。如果存储&str值,容器的生命周期将限于借用字符串的生命周期。

如果您的解析器生成器生成具有如下签名的解析函数:

smtp_parser::host<'a>(&'a str) -> SmtpHost<'a>
Run Code Online (Sandbox Code Playgroud)

然后,当它传递给您一个&str供您用来构造解析树/解析值时,它很可能会为您提供输入的子字符串。这意味着&str您存储在SmtpHost枚举中的生命周期必须短于原始输入字符串。事实上,你可以在签名中看到这一点;输入字符串和输出SmtpHost都有生命周期参数'a

这意味着您的结果SmtpHost不能比用于生成它的输入寿命更长。如果输入是字符串常量 ,&'static str这可能没问题,但如果您从标准输入或读取文件中获取输入,则将无法返回超过SmtpHost输入字符串所属点的内容。

例如,假设您想声明一个解析SmtpHostfrom 标准的函数:

fn read_host<'a>() -> SmtpHost<'a> {
    let mut line = String::new();
    let stdin = io::stdin();
    stdin.lock().read_line(&mut line).expect("Could not read line");
    smtp_parser::host(&line)
}
Run Code Online (Sandbox Code Playgroud)

您会收到一条错误消息,提示“线路寿命不够长”。这是 Rust Playground 中的一个简单示例

因此,&str当您只是从其他地方借用一个不需要比源寿命更长的值时,应该使用它。String当您需要拥有该值的所有权时,应该使用。

对于更复杂的情况,您需要拥有一个拥有的值,但希望能够在多个地方使用它,而不需要拥有它的许多副本,为此,有Rc<T>Rc<RefCell<T>。但就你而言,听起来SmtpHost应该只拥有它存储的字符串的所有权。