Skip to content

Latest commit

 

History

History
78 lines (62 loc) · 4.74 KB

creating-a-rust-function-that-accepts-string-or-str.md

File metadata and controls

78 lines (62 loc) · 4.74 KB

#Creating a Rust function that accepts String or &str 创建一个接受String或&str的Rust函数

在我的上一篇博文 我们谈了很多关于使用&str作为函数接受一个string参数的优选。在那篇文章快结尾时,我们讨论了一些何时在结构中使用String还是&str。我认为这个建议是好的,但在有些情况下,使用&str代替string不是最优的,我们需要另一种策略来对付这些使用用例。

#A struct Containing Strings 包含字符串的结构

考虑如下Person结构。为了讨论,让我们假设Person有一个真正需要拥有所有权的name变量。因此我们选择使用String类型而不是&str。

struct Person {
    name: String,
}

现在我们需要实现一个new()函数。根据我的上一篇博客的讨论,我们倾向使用&str:

impl Person {
    fn new (name: &str) -> Person {
        Person { name: name.to_string() }
    }
}

只要我们记得在new()函数里调用.to_string(),上述代码可以工作。然而,这个函数的人体工程学设计的不太理想。如果我们使用string字面量,那么我们可以像Person.new("Herman")那样创建一个新的Person。如果我们已经有一个String,我们需要一个引用来指向这个String:

let name = "Herman".to_string(); //String
let person = Person::new(name.as_ref());

这感觉就像我们在兜圈子。我们有一个String,然后我们调用as_ref()把它变成一个&str,然后把它放回了new()函数,使用.to_stirng()再把它变回String。我们可以回去,使用一个String像使用fn new(name: String) -> Person {,但这意味着我们需要强迫调用者当使用string字面量时要.to_string()

#Into conversions Into转换

我们可以用Into trait来使我们的函数更容易被使用者调用。这一特性将自动转换为一个&str到一个string。如果我们已经有了一个String,则没有转换发生。

struct Person {
    name: String,
}

impl Person {
    fn new<S: Into<String>>(name: S) -> Person {
        Person { name: name.into() }
    }
}

fn main() {
    let person = Person::new("Herman");  //&str
    let person = Person::new("Herman".to_string()); //String
}

这个new()语法看起来有点不同。我们使用泛型特性来告诉Rust那个S类型必须为Sring类型实现Into特质。String类型实现Into<String>为空操作,因为我们已经有一个String。 &str类型实现Into<String>采用相同的.to_string()方法像在我们原本在new()函数做的那样。所以我们不是回避需要.to_string()调用,但我们正在为调用者取走调用需求。你可能会问,如果使用Into<String>会影响性能吗,答案是否定的。Rust使用静态调度单型的概念在编译期来处理所有的这些。

别担心那些像静态调度和单型的事情会混淆不清。你只需要知道使用上面的语法你可以创建一个可以同时接受String和&str的函数。如果你认为fn new<S: Into<String>>(name:S) -> Person {拥有大量的语法,它是。重要的是要指出,Into<String>没有什么特别的,它只是一个特性,是Rust标准库的一部分。如果你想的话,你可以自己实现这一特性。你可以实现类似的你发现有用的特质并把他们发布到crates.io。所有这些用户创建能力使得Rust成为一个令人敬畏的语言。

#Another Way To Write Person::new() 另外一种写Person::new()的方法

下面的另外一种写法在语法上可能更容易阅读,尤其是当函数签名变得更加复杂:

struct Person {
    name: String,
}

impl Person {
    fn new<S>(name: S) -> Person where S: Into<String> {
        Person { name: name.into() }
    }
}

#相关链接