smo*_*kku 34 interface traits rust
在我看来,Rust 和traitJava 是一样的interface——一组需要在对象上实现的函数。
trait没有命名它是出于技术原因interface还是只是出于某种偏好?
Kev*_*eid 61
Rust 特征和 Java 接口都解决了具有多种可能的实现的问题,这些实现遵循某些约定/协议/接口来与值/对象交互,而不像 Java 超类那样限制实现细节。它们可用于许多相同的情况。然而,它们在许多细节上有所不同,主要意味着 Rust 特征更强大:
\nJava 接口要求实现对象具有具有特定名称的方法。每个 Rust 特征都有一个完全独立的命名空间。在 Java 中,两个接口可能无法一起实现:
\ninterface Foo {\n void someMethod();\n}\ninterface Bar {\n int someMethod();\n}\nclass TwoInterfaces implements Foo, Bar {\n public int someMethod(); // The return type must be void and also must be int\n}\nRun Code Online (Sandbox Code Playgroud)\n在 Rust 中,当您实现类型的特征时,您可以使用impl指定该特征的单独块来实现,因此每个方法/函数属于哪个特征是明确的。这意味着实现类型的特征不能与不同的特征冲突(除非在作用域内具有这两种特征的调用站点,必须使用函数语法而不是方法语法来消除歧义)。
Java 特征可以具有泛型(类型参数),SomeInterface<T>但对象只能实现接口一次。
class TwoGenerics implements Foo<Integer>, Foo<String> {\n public void someMethod(??? value) {} // Can\'t implement, must be one method\n}\ninterface Foo<T> {\n void someMethod(T value);\n}\nRun Code Online (Sandbox Code Playgroud)\n在 Rust 中,一个特征可以实现多种类型,这些基本上被视为不同的特征:
\nstruct TwoGenerics;\n\ntrait Foo<T> {\n fn some_method(&self, input: T);\n}\n\nimpl Foo<i32> for TwoGenerics {\n fn some_method(&self, input: i32) {}\n}\nimpl Foo<String> for TwoGenerics {\n fn some_method(&self, input: String) {}\n}\nRun Code Online (Sandbox Code Playgroud)\n要获得类似于 Java 的行为,即要求任何实现类型都必须有一种特定类型,您可以定义关联类型而不是泛型:
\nstruct TwoGenerics;\n\ntrait Foo<T> {\n fn some_method(&self, input: T);\n}\n\nimpl Foo<i32> for TwoGenerics {\n fn some_method(&self, input: i32) {}\n}\nimpl Foo<String> for TwoGenerics {\n fn some_method(&self, input: String) {}\n}\nRun Code Online (Sandbox Code Playgroud)\n在 Rust 中,如果您定义了特征,则可以为您未定义的类型实现该特征。因此,您可以在板条箱中定义一个特征,然后在标准库(或您依赖的其他库)中为相关类型实现它,例如序列化、随机生成、遍历等。在 Java 中,可以使用 run-需要时间类型检查才能获得类似的结果。
\n在 Rust 中,特征可能具有适用于满足某些条件(边界)的所有类型的泛型实现,或者仅在其参数合适时才适用于特定泛型类型的实现。例如,在标准库中,有(大约)
\nstruct Thing;\n\ntrait Foo {\n type Input;\n fn some_method(&self, input: Self::Input);\n}\n\nimpl Foo for Thing {\n type Input = i32;\n fn some_method(&self, input: i32) {}\n}\nRun Code Online (Sandbox Code Playgroud)\n所以 aVec是可克隆的当且仅当它的内容是可克隆的。在 Java 中,类不能有条件地实现接口,这对于任何递归属性来说都是有问题的:例如,list instanceof Serializable可能为 true,而列表将无法序列化,因为它的一个或多个元素不可序列化。
Rust 特征可能具有关联的常量、类型和非方法函数(类似于 Javastatic方法),所有这些对于每个实现类型都可能不同。当 Java 接口有static成员时,整个接口只有一个实现。
例如, Rust 中的特征允许通过调用或Default来构造任何实现类型的新实例。在Java中,您需要创建一个由单独的 \xe2\x80\x9cfactory\xe2\x80\x9d 类实现的接口来执行此操作(但是工厂可以拥有自己的状态/数据,因此您仍然可以选择使用工厂Rust 中的特征和类型)。Default::default()T::default()
Rust 特征可以具有接受多个输入(或产生输出)的函数,这些输入也属于实现类型。Java 接口不能引用实现类型;他们只能添加不需要相同的类型参数。(另一方面,Java 具有子类化(子类型),而 Rust 没有,因此当您拥有不同具体类型但相同超类型的实例集合时,情况必然会更加复杂。)
\n可能还有更多细节可以提及,但我认为这些涵盖了您可以或必须以不同方式使用它们的很多方式,即使它们用于相同的任务。
\n至于名称\ xe2\x80\x9ctrait\xe2\x80\x9d 与 \xe2\x80\x9cinterface\xe2\x80\x9d,这是由于计算机科学中现有的特征概念,它被认为具有几个特定的属性,主要是在实现和使用特征时不涉及继承和重写。这与我上面提到的 \xe2\x80\x9cseparate 命名空间\xe2\x80\x9d 密切相关。
\nMax*_*nko 10
Interface是面向对象编程的一个概念。当您说对象类型实现接口时,您正在谈论该类型的属性。它表示该类型遵循一定的约定。
Rust 不是面向对象的语言。并且traits不完全是接口。当您说结构体有 some 时trait,并不一定意味着它是该结构体的属性,而是该结构体映射了该特征的功能。
例如,您可以有一个内置的 Rust 类型[f32; 2]- 具有两个值的数组。你可以有一个特质Point:
trait Point {
fn x(&self) -> f32;
fn y(&self) -> f32;
}
Run Code Online (Sandbox Code Playgroud)
作为特征的作者,您可以决定类型是否[f32; 2]很好地映射到该特征的功能。您可以为该类型实现此特征:
impl Point for [f32; 2] {
fn x(&self) -> f32 { self[0] }
fn y(&self) -> f32 { self[1] }
}
Run Code Online (Sandbox Code Playgroud)
这样做并没有改变类型本身,而是表明它具有你的特征。
这是你不能用接口做但可以用特征做的一件事。我相信trait选择这个名称而不是interface为 rust 选择是为了强调这种区别并防止概念混淆。