作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
定义泛型时 struct
,有没有办法在 rust 使用给定泛型类型T
实现特征的方法的不同实现?
例如:
struct S<T> {
value: T,
}
impl<T> S<T> {
fn print_me(&self) {
println!("I cannot be printed");
}
}
impl<T: std::fmt::Display> S<T> {
fn print_me(&self) {
println!("{}", self.value);
}
}
fn main() {
let s = S { value: 2 };
s.print_me();
}
最佳答案
有一个称为 specialization
的不稳定功能。允许多个 impl
只要其中一个 block 比另一个更具体, block 即可应用于相同类型:
#![feature(specialization)]
struct Printer<T>(T);
trait Print {
fn print(&self);
}
// specialized implementation
impl<T: fmt::Display> Print for Printer<T> {
fn print(&self) {
println!("{}", self.0);
}
}
// default implementation
impl<T> Print for Printer<T> {
default fn print(&self) {
println!("I cannot be printed");
}
}
struct NotDisplay;
fn main() {
let not_printable = Printer(NotDisplay);
let printable = Printer("Hello World");
not_printable.print();
printable.print();
}
// => I cannot be printed
// => Hello World
在稳定的 Rust 上,我们需要一些其他机制来完成特化。 Rust 有另一个语言特性可以做到这一点:
method resolution autoref .编译器的规则是,如果一个方法可以在没有 autoref 的情况下被调度,那么它将是。只有在没有 autoref 的情况下无法调度方法时,编译器才会插入 autoref 并尝试再次解析它。所以在这个例子中:
impl Print for Value {
fn print(self) {
println!("Called on Value");
}
}
impl Print for &Value {
fn print(self) {
println!("Called on &Value");
}
}
Value
的实现将优先于
&Value
.知道了这条规则,我们就可以模仿稳定 Rust 的特化:
struct Printer<T>(T);
trait Print {
fn print(&self);
}
// specialized implementation
impl<T: fmt::Display> Print for Printer<T> {
fn print(&self) {
println!("{}", self.0);
}
}
trait DefaultPrint {
fn print(&self);
}
// default implementation
//
// Note that the Self type of this impl is &Printer<T> and so the
// method argument is actually &&T!
// That makes this impl lower priority during method
// resolution than the implementation for `Print` above.
impl<T> DefaultPrint for &Printer<T> {
fn print(&self) {
println!("I cannot be printed");
}
}
struct NotDisplay;
fn main() {
let not_printable = Printer(NotDisplay);
let printable = Printer("Hello World");
(¬_printable).print();
(&printable).print();
}
// => I cannot be printed
// => Hello World
编译器将尝试使用
Print
先执行。如果不能(因为类型不是
Display
),它将使用更通用的
DefaultPrint
实现.
DefaultPrint
或
Print
)之间进行选择:
fn print<T: ???>(value: T) {
(&value).print()
}
然而,这个技巧对宏非常有用,宏不需要拼写 trait bound:
macro_rules! print {
($e:expr) => {
(&$e).print()
};
}
print!(not_printable); // => I cannot be printed
print!(printable); // => Hello World
关于generics - 取决于特征的通用实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64955738/
我是一名优秀的程序员,十分优秀!