在传统的面向对象语言(例如Java)中,可以通过从重写版本的超类调用原始方法来"扩展"继承类中方法的功能,例如:

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关键字从超类调用原始版本.我能够获得遗传特征的等效行为,但在为 struct 实现特征时却不行.

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"
}

因此,在继承特性的情况下,调用原始默认实现没有问题,但是,在实现 struct 时使用相同的语法会表现出不同的行为.这是铁 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中运行良好的设计不能也不应该被强制1对1地 rust 迹斑斑.

    Foo::method(self);  // this apparently calls this overridden
                        // version, because it overflows the stack

限定路径语法Trait::method(value)<Type as Trait>::method(value)的sugar,其中Typevalue的类型(或者,可能是取消引用若干次后的类型).也就是说,它正在调用您发现的特定类型的方法.

Rust相关问答推荐

Rust kill std::processs::child

在HashMap中插入Vacant条目的可变借位问题

有没有一种惯用的方法来判断VEC中是否存在变体?

写入引用会更新基础值,但引用会打印意外的值

为什么Option类型try块需要类型注释?

习语选项<;T>;到选项<;U>;当T->;U用From定义

链表堆栈溢出

Rust面向对象设计模式

Const 上下文:从 init 函数创建具有 const 通用长度的数组

使用占位符获取用户输入

如何以与平台无关的方式将OsString转换为utf-8编码的字符串?

`use` 和 `crate` 关键字在 Rust 项目中效果不佳

将泛型中的 Box 转换为 rust 中的 Box

如何在 Rust 中按 char 对字符串向量进行排序?

是否可以预测堆栈溢出?

第 7.4 章片段中如何定义 `thread_rng`

只有一个字符被读入作为词法分析器的输入

意外的正则表达式模式匹配

如何在 Rust 中构建一个 str

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