我对Rust 完全陌生.我创建了一个程序来存储有关接触这种语言的人的信息:

person.rs个个

pub struct Person {
    firstname: String,
    lastname: String,
    pub age: u8
}


impl Person {
    pub fn new(firstname: String, lastname: String, age: u8) -> Person {
        return Person { firstname: firstname, lastname: lastname, age: age };
    }

    pub fn from_str(firstname: &str, lastname: &str, age: u8) -> Person {
        return Person::new(firstname.to_string(), lastname.to_string(), age);
    }

    pub fn name(&self) -> String {
        return self.firstname.to_owned() + " " + &self.lastname;
    }
}

main.rs个个

mod person;
use person::Person;


fn main() {
    let me = Person::from_str("John", "Doe", 42);
    println!("{} is {} years old.", me.name(), me.age);
}

据我所知,铁 rust 中没有函数超载. 然而,我读到过一个叫"特征"的概念,我还没有完全理解. 它们的行为是否类似于C++中的模板(我也不是C++专家)? 有没有其他方法,比如使用特征,这样我就可以写Person::new()来接受String&str

我试着这样做,但没有效果:

person.rs个个

pub struct Person {
    firstname: String,
    lastname: String,
    pub age: u8
}


impl Person {
    /*
    pub fn new(firstname: String, lastname: String, age: u8) -> Person {
        return Person { firstname: firstname, lastname: lastname, age: age };
    }

    pub fn from_str(firstname: &str, lastname: &str, age: u8) -> Person {
        return Person::new(firstname.to_string(), lastname.to_string(), age);
    }
    */
    
    pub fn new<T>(firstname: &T, lastname: &T, age: u8) -> Person {
        return Person::new(firstname.to_string(), lastname.to_string(), age);
    }

    pub fn name(&self) -> String {
        return self.firstname.to_owned() + " " + &self.lastname;
    }
}

main.rs个个

mod person;
use person::Person;


fn main() {
    let me = Person::new("John", "Doe", 42);
    println!("{} is {} years old.", me.name(), me.age);
}

结果是:

$ rustc main.rs -o main
error[E0599]: the method `to_string` exists for reference `&T`, but its trait bounds were not satisfied
  --> person.rs:20:38
   |
20 |         return Person::new(firstname.to_string(), lastname.to_string(), age);
   |                                      ^^^^^^^^^ method cannot be called on `&T` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `T: std::fmt::Display`
           which is required by `T: ToString`
           `&T: std::fmt::Display`
           which is required by `&T: ToString`

error[E0599]: the method `to_string` exists for reference `&T`, but its trait bounds were not satisfied
  --> person.rs:20:60
   |
20 |         return Person::new(firstname.to_string(), lastname.to_string(), age);
   |                                                            ^^^^^^^^^ method cannot be called on `&T` due to unsatisfied trait bounds
   |
   = note: the following trait bounds were not satisfied:
           `T: std::fmt::Display`
           which is required by `T: ToString`
           `&T: std::fmt::Display`
           which is required by `&T: ToString`

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> main.rs:6:14
   |
6  |     let me = Person::new("John", "Doe", 42);
   |              ^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
note: required by a bound in `Person::new`
  --> person.rs:19:16
   |
19 |     pub fn new<T>(firstname: &T, lastname: &T, age: u8) -> Person {
   |                ^ required by this bound in `Person::new`
help: consider relaxing the implicit `Sized` restriction
  --> person.rs:19:17
   |
19 |     pub fn new<T: ?Sized>(firstname: &T, lastname: &T, age: u8) -> Person {
   |                 ++++++++

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.

推荐答案

Ruust具有泛型,而不是模板.泛型可以由特征限定,这些特征为标准接口提供了一个系统.

在你的情况下,你需要的是一种trait ,让你从String分或&str分中得到String分.你有几个 Select ,但我会 Select Into<String>.

您可以执行以下操作:

    pub fn new(firstname: impl Into<String>, lastname: impl Into<String>, age: u8) -> Person {
        Person {
            firstname: firstname.into(),
            lastname: lastname.into(),
            age
        }
    }

从本质上讲,这是在说:

  • 新是一种功能
  • 这需要三个论点
  • 前两个参数可以是实现Into<String>的任何类型
  • 最后一个参数必须是u8

Into<T>是铁 rust 中用于转换的标准特性.它定义了一个关联的fn into(self) -> T,该关联fn into(self) -> T通过值获取给定对象并返回目标T.

Into实际上只是From<T>的补充帮助器特性,它有一个关联的fn from(other: T) -> Self,它接受某个其他类型并返回您想要的类型.

From有一个自反实现,这基本上意味着对于任何类型,您都可以执行T::from(x),其中xT类型.这也适用于Into,因此任何类型都可以转换为into本身,这就是为什么String可以在编译器期望Into<String>的情况下工作.

Rust相关问答推荐

是否有可能同时避免不兼容的不透明类型和代码重复?

在不重写/专门化整个函数的情况下添加单个匹配手臂到特征的方法?

在Rust中宏的表达式中提取对象

如何导入crate-type=[";cdylib;]库?

作为1字节位掩码的布尔值 struct

`RwLockWriteGuard_,T`不实现T实现的特征

程序在频道RX上挂起

将Vec<;U8&>转换为Vec<;{Float}&>

获取已知数量的输入

为什么在 Allocator API 中 allocate() 使用 `[u8]` 而 deallocate 使用 `u8` ?

从 rust 函数返回 &HashMap

使用 Option 来分配?

如何为已实现其他相关 std trait 的每个类型实现一个 std Trait

特征中定义的类型与一般定义的类型之间的区别

为什么可以在迭代器引用上调用 into_iter?

从现有系列和 map 值创建新系列

我如何将特征作为 struct 的拥有字段?

具有生命周期和以后引用的可变方法

如何在 Rust 的泛型函​​数中同时使用非拥有迭代器和消费迭代器?

为什么当borrow 变量发生变化时,borrow 变量不会改变?