是否可以扩展结构中特征的默认方法实现?
Is it possible to extend a default method implementation of a trait in a struct?
在传统的面向对象语言中(例如 Java),可以 "extend" 继承 class 中方法的功能,方法是从父级调用原始方法class 在覆盖版本中,例如:
class A {
public void method() {
System.out.println("I am doing some serious stuff!");
}
}
class B extends A {
@Override
public void method() {
super.method(); // here we call the original version
System.out.println("And I'm doing something more!");
}
}
如您所见,在 Java 中,我可以使用 super
关键字从超级 class 调用原始版本。我能够获得继承特征的等效行为,但在实现结构特征时却没有。
trait Foo {
fn method(&self) {
println!("default implementation");
}
}
trait Boo: Foo {
fn method(&self) {
// this is overriding the default implementation
Foo::method(self); // here, we successfully call the original
// this is tested to work properly
println!("I am doing something more.");
}
}
struct Bar;
impl Foo for Bar {
fn method(&self) {
// this is overriding the default implementation as well
Foo::method(self); // this apparently calls this overridden
// version, because it overflows the stack
println!("Hey, I'm doing something entirely different!");
println!("Actually, I never get to this point, 'cause I crash.");
}
}
fn main() {
let b = Bar;
b.method(); // results in "thread '<main>' has overflowed its stack"
}
因此,在继承特征的情况下,调用原始默认实现是没有问题的,但是,在实现结构时使用相同的语法会表现出不同的行为。这是 Rust 中的问题吗?有办法解决吗?或者我只是错过了什么?
Is this a problem within Rust?
不,这是按预期工作的
Is there a way around it?
您可以将方法移动到一个自由函数中,然后直接调用它,一次从默认方法,一次从 "overridden" 方法。
fn the_default() {
println!("default implementation");
}
trait Foo {
fn method(&self) {
the_default()
}
}
struct Bar;
impl Foo for Bar {
fn method(&self) {
the_default();
println!("Hey, I'm doing something entirely different!");
}
}
fn main() {
let b = Bar;
b.method();
}
Or am I just missing something?
Rust 不是一种面向对象的语言,Rust 可能是一种面向对象的语言,但并不是所有的 OO 语言都是一样的。 Rust 可能不太符合您期望的传统范例。
也就是说,特征在 运行 时不存在。只有当它们应用于结构并与结构一起使用时,才会生成可调用的代码。当您创建自己的方法实现时,它会取代默认实现;默认方法实现无处可存在。
很多时候,您的代码可以用不同的方式编写。也许真正共享的代码应该作为新结构上的方法提取,或者您可能为方法提供闭包以自定义行为。
现在不能直接这样做。
但是,RFC 1210: impl
specialization 包含使这种行为起作用的各个方面,例如,像这样的东西应该起作用:
trait Foo {
fn method(&self) { println!("default implementation"); }
}
trait Bar: Foo { ... }
partial impl<T: Bar> Foo for T {
default fn method(&self) { println!("Bar default"); }
}
super
调用被明确提及为 an extension,因此不一定会立即出现,但可能会在将来出现。
同时,通常采用的做法是为默认行为定义一个单独的函数,并在默认方法中调用,然后用户可以直接调用该函数来模拟super::...
调用:
trait Foo {
fn method(&self) { do_method(self) }
}
fn do_method<T: Foo>(_x: &T) {
println!("default implementation");
}
impl Foo for Bar {
fn method(&self) {
do_method(self);
println!("more");
}
}
也就是说,Rust 更喜欢组合而不是继承:在 Java 中运行良好的设计不能也不应该一对一地强制到 Rust 中。
Foo::method(self); // this apparently calls this overridden
// version, because it overflows the stack
限定路径语法,Trait::method(value)
是 <Type as Trait>::method(value)
的糖分,其中 Type
是 value
的类型(或者,可能是取消引用某些数量后的类型次)。也就是说,它正在调用您发现的特定类型的方法。
实现此目的的另一种方法是将重写方法放在结构 impl
块中
trait A {
fn a(&self) {
println!("trait default method");
}
}
struct B;
impl B {
fn a(&self) {
println!("overridden method");
// call default method here
A::a(self);
}
}
impl A for B {}
fn main() {
let a = B;
a.a();
}
在传统的面向对象语言中(例如 Java),可以 "extend" 继承 class 中方法的功能,方法是从父级调用原始方法class 在覆盖版本中,例如:
class A {
public void method() {
System.out.println("I am doing some serious stuff!");
}
}
class B extends A {
@Override
public void method() {
super.method(); // here we call the original version
System.out.println("And I'm doing something more!");
}
}
如您所见,在 Java 中,我可以使用 super
关键字从超级 class 调用原始版本。我能够获得继承特征的等效行为,但在实现结构特征时却没有。
trait Foo {
fn method(&self) {
println!("default implementation");
}
}
trait Boo: Foo {
fn method(&self) {
// this is overriding the default implementation
Foo::method(self); // here, we successfully call the original
// this is tested to work properly
println!("I am doing something more.");
}
}
struct Bar;
impl Foo for Bar {
fn method(&self) {
// this is overriding the default implementation as well
Foo::method(self); // this apparently calls this overridden
// version, because it overflows the stack
println!("Hey, I'm doing something entirely different!");
println!("Actually, I never get to this point, 'cause I crash.");
}
}
fn main() {
let b = Bar;
b.method(); // results in "thread '<main>' has overflowed its stack"
}
因此,在继承特征的情况下,调用原始默认实现是没有问题的,但是,在实现结构时使用相同的语法会表现出不同的行为。这是 Rust 中的问题吗?有办法解决吗?或者我只是错过了什么?
Is this a problem within Rust?
不,这是按预期工作的
Is there a way around it?
您可以将方法移动到一个自由函数中,然后直接调用它,一次从默认方法,一次从 "overridden" 方法。
fn the_default() {
println!("default implementation");
}
trait Foo {
fn method(&self) {
the_default()
}
}
struct Bar;
impl Foo for Bar {
fn method(&self) {
the_default();
println!("Hey, I'm doing something entirely different!");
}
}
fn main() {
let b = Bar;
b.method();
}
Or am I just missing something?
Rust 不是一种面向对象的语言,Rust 可能是一种面向对象的语言,但并不是所有的 OO 语言都是一样的。 Rust 可能不太符合您期望的传统范例。
也就是说,特征在 运行 时不存在。只有当它们应用于结构并与结构一起使用时,才会生成可调用的代码。当您创建自己的方法实现时,它会取代默认实现;默认方法实现无处可存在。
很多时候,您的代码可以用不同的方式编写。也许真正共享的代码应该作为新结构上的方法提取,或者您可能为方法提供闭包以自定义行为。
现在不能直接这样做。
但是,RFC 1210: impl
specialization 包含使这种行为起作用的各个方面,例如,像这样的东西应该起作用:
trait Foo {
fn method(&self) { println!("default implementation"); }
}
trait Bar: Foo { ... }
partial impl<T: Bar> Foo for T {
default fn method(&self) { println!("Bar default"); }
}
super
调用被明确提及为 an extension,因此不一定会立即出现,但可能会在将来出现。
同时,通常采用的做法是为默认行为定义一个单独的函数,并在默认方法中调用,然后用户可以直接调用该函数来模拟super::...
调用:
trait Foo {
fn method(&self) { do_method(self) }
}
fn do_method<T: Foo>(_x: &T) {
println!("default implementation");
}
impl Foo for Bar {
fn method(&self) {
do_method(self);
println!("more");
}
}
也就是说,Rust 更喜欢组合而不是继承:在 Java 中运行良好的设计不能也不应该一对一地强制到 Rust 中。
Foo::method(self); // this apparently calls this overridden // version, because it overflows the stack
限定路径语法,Trait::method(value)
是 <Type as Trait>::method(value)
的糖分,其中 Type
是 value
的类型(或者,可能是取消引用某些数量后的类型次)。也就是说,它正在调用您发现的特定类型的方法。
实现此目的的另一种方法是将重写方法放在结构 impl
块中
trait A {
fn a(&self) {
println!("trait default method");
}
}
struct B;
impl B {
fn a(&self) {
println!("overridden method");
// call default method here
A::a(self);
}
}
impl A for B {}
fn main() {
let a = B;
a.a();
}