gpt4 book ai didi

generics - 取决于特征的通用实现

转载 作者:行者123 更新时间:2023-12-03 11:28:29 24 4
gpt4 key购买 nike

定义泛型时 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");

(&not_printable).print();
(&printable).print();
}

// => I cannot be printed
// => Hello World
编译器将尝试使用 Print先执行。如果不能(因为类型不是 Display ),它将使用更通用的 DefaultPrint 实现.
这种技术应用方法解析的方式不能用特征绑定(bind)来描述,因此它不适用于常规方法,因为我们必须在特征之一( DefaultPrintPrint )之间进行选择:
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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com