繁体   English   中英

如何以及何时在 Rust 的 impl 块中使用泛型类型参数?

[英]How and when to use the generic type parameter in impl block in Rust?

我对 Rust 中impl关键字的泛型参数感到困惑。

为了解释我的困惑,我目前正在进行沙沙练习。 我正在做泛型部分。 这里可以看到的第二个问题是使Wrapper结构通用。

很简单,解决方法是:

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    pub fn new(value: T) -> Self {
        Wrapper { value }
    }
}

但是我问自己,为什么impl还必须有一个类型参数? 为什么impl<T> Wrapper<T>而不仅仅是impl Wrapper<T>

我无法回答这个问题,但在继续下一个练习时,可以看到这里还有另一个通用问题,我通过以下方式解决了这个问题:

use std::fmt::Display;

pub struct ReportCard<T:Display> {
    pub grade: T,
    pub student_name: String,
    pub student_age: u8,
}

impl<T:Display> ReportCard<T> {
    pub fn print(&self) -> String {
        format!("{} ({}) - achieved a grade of {}",
            &self.student_name, &self.student_age, &self.grade.to_string())
    }
}

现在我想知道,为什么这是对的,而以下是错误的:

pub struct ReportCard<T:Display> {
    pub grade: T,
    pub student_name: String,
    pub student_age: u8,
}

impl<T:Display> ReportCard<T:Display> {
    pub fn print(&self) -> String {
        format!("{} ({}) - achieved a grade of {}",
            &self.student_name, &self.student_age, &self.grade.to_string())
    }
}

我认为我的问题的症结在于,我不太了解泛型语法。 以及在哪里放置泛型类型参数,特别是当有一个impl块时。

有没有人解释应该如何使用这些语法?

你可以把它想象成函数接受参数的方式,并且可以在函数调用中反馈这些参数,这可能是有意义的。

泛型类型Wrapper<T> “类似于”一个接受类型T并生成实际的具体类型Wrapper<T>的函数(即使语法没有区别,就像定义时没有区别一样)一个函数,当您调用它以从中获取实际值时)。

类似地,一个impl块“就像”一个可以接受一些参数的函数,并为给定类型生成给定实现。 也就是说, impl<T> Wrapper<T> { ... }应该被理解为定义一个通用实现,它接受一个参数T ,并为具体类型Wrapper<T>生成一个实际的具体实现{ ... } Wrapper<T> ,在这种情况下,可以将其视为“函数调用”而不是“签名声明”。

但是,例如,您也可以选择不使您的实现通用: impl Wrapper<u32> { ... } ,或者甚至使其在多个参数上通用,不在Wrapper<T> “调用”中使用 none: impl<T, U> Wrapper<char> { ... }因为这些类型参数也可以在实际实现中使用。


话虽如此,我们现在可以更详细地查看语法。 通常,当您定义“通用块”(即,通用impl或通用struct或通用enum或...)时,该块的第一个关键字也可能使用<T, U, ...>语法,您可能会将其视为函数定义。 通过相同语法在块中对这些类型的每次后续使用都可能被视为“函数调用”:您将这些参数提供给另一个“函数”。

出于这个原因,您只能在impl块的第一个<...>部分中添加对这些类型的约束,而不是在类型之后:

impl<T: Display> Wrapper<T> { ... }

是有效的,因为它意味着给定一个类型T使得T实现特征Display ,我可以提供具体类型Wrapper<T>的实现,但是

impl<T: Display> Wrapper<T: Display> { ... }

无效,也不是

impl<T> Wrapper<T: Display> { ... }

因为您正在对“函数调用”施加约束。 就像

fn something(a: usize) {
  something_else(a);
}

是有效的,但不是

fn something(a: usize) {
  something_else(a: usize)
}

也不

fn something(a) {
  something_else(a: usize)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM