我必须“使用”一个trait才能调用该trait中定义的方法吗?

4

我正在尝试使用cgmath库。我有以下main.rs文件:

extern crate cgmath;

use cgmath::vector::{Vector3, EuclideanVector};

fn main() {
    let mypoint = Vector3 { x: 1f64, y: 1f64, z: 3f64 };

    println!("The length of the vector is {}, and the length squared is {}", mypoint.length(), mypoint.length2());
}

在我的使用中,当我省略EuclideanVector时,会出现以下编译错误:
type 'cgmath::vector::Vector3<f64>' does not implement any method in scope named 'length'

看起来 Rust 编译器无法找到 length() 方法,除非我导入 Vector3 使用的 traits 之一。深入 源代码,似乎 length 方法在 EuclideanVector trait 中定义。
直觉上,我不应该需要导入一个 trait 来使用继承了该 trait 的类型。我是否缺少某种技巧?这是 cgmath 库特有的细微差别吗?这是 Rust 的惯用方式,我应该习惯这样做吗?

可能是为什么需要导入一个trait才能使用它的类型实现的重复问题。 - Chris Morgan
4个回答

6
您在考虑继承方面的特征。如果您将特征视为可重载的模块,则可能更有意义,与 Self 类型相关。从这个角度来看,特征必须在范围内,编译器才能知道其方法,就像必须在范围内使用模块一样。这种情况的一个特定含义是,实现可以声明在它们实现的特征旁边,而不是它们实现的类型旁边。在这种情况下,显然,如果您的代码不知道这个特征,它就不能使用它的方法。
当前行为的另一个动机是多个特征可以定义具有相同名称的方法,并且当您对实现为同一类型的特征存在此类冲突时,您无法再使用方法调用语法访问它们的方法。相反,您必须使用函数调用语法,以指定该方法是属于哪个特征的成员(特征充当方法所在的模块)。如果方法调用语法使用了程序中的所有特征,而不仅仅是方法解析范围内的那些,那么您将经常遇到这些冲突,因为您会与代码未直接使用的特征中的方法名称发生冲突。

3

严格地说,您并不一定需要使用use。您可以选择以下方式:

(&mypoint as &cgmath::vector::EuclideanVector).length2()

这实际上是一个类型转换,只有当“as”的右侧可以转换为对象时才有效。 - real-or-random

1
如果您真的不想导入,您可以调用cgmath::vector::EuclideanVector::length(&mypoint)
(我不知道在提问时是否可行。)

1
是的,这就是 Rust 的工作方式。在使用其方法之前,您必须始终导入 trait。这是有意为之的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接