为什么有时我需要在Rust中“使用”我实际上并未使用的东西?

huangapple go评论65阅读模式
英文:

Why Do I Need To "Use" Things Sometimes That I'm Not Really Using In Rust?

问题

这段代码在编译时出现了奇怪的错误,"no method named num_days_from_ce found for struct NaiveDate in the current scope"。这是因为您需要手动导入Datelike,才能使用num_days_from_ce方法。这是因为在Rust中,有时需要明确导入依赖,即使您没有直接使用它们。这是Rust中的一种设计决策,为了确保代码的清晰性和可维护性。

至于为什么编译器不建议应该导入什么,这可能是Rust编译器的功能限制,或者它可能会在将来的版本中改进。对于不使用的导入,编译器会发出警告,但这并不会影响最终的可执行文件。

这是Rust语言的一个特性,旨在鼓励开发人员编写干净、明晰的代码。如果您有其他问题或需要进一步的帮助,请告诉我。

英文:

Consider this code:

use chrono::{Local, NaiveDate};

fn main() {
    let d = Local::now().naive_local().date();
    println!("{}", d.num_days_from_ce());
}

This fails to compile with the strange error, "no method named num_days_from_ce found for struct NaiveDate in the current scope".

What? No method name? It's right there in the documentation‽

It took me a while to figure out I needed to add Datelike to the things I'm using from chrono. So my question is, why? Why force the consumers to have to import dependencies manually that we aren't using directly? This is not the only case of these necessary phantom imports in Rust... 🧐

Maybe there is something about Rust that I am not understanding here, or maybe there is something that can be changed about this library so that consumers don't need to use DateLike in this situation.

Also, why can't the compiler recommend WHAT to bring into the current scope?

Another issue with this syntax is that it produces a compiler warning that these necessary phantom imports are unused. Thus, there is no possible way for my code to compile cleanly... 😔

warning: unused imports: `Datelike`, `NaiveDate`, `Weekday`
  --> src/bin/foo/bar.rs:25:18
   |
25 |     use chrono::{Datelike, Duration, Local, NaiveDate, Weekday};
   |                  ^^^^^^^^                   ^^^^^^^^^  ^^^^^^^

答案1

得分: 2

Rust 有一个规则,除非 trait 处于作用域内,否则不能使用 trait 方法。如果 trait 不在作用域内,你仍然可以使用这些函数,只是不能使用后缀方法语法。

use chrono::Local;

fn main() {
    let d = Local::now().naive_local().date();
    println!("{}", chrono::Datelike::num_days_from_ce(&d));
}

但在几乎所有情况下,你会将 trait 引入作用域并使用方法语法。许多标准库的 trait,如 Iterator,会被自动导入。

这个规则存在是出于 API 原因。任何人都可以在外部类型上实现一个 trait,因此如果你的两个依赖都有一个带有相同名称方法的 trait,就会产生歧义。依赖项没有顺序,因此选择一个而不是另一个会产生歧义。如果这导致错误,那将意味着实现 trait 的 crate 可能会破坏 API。相反,Rust 要求将 trait 引入作用域,以避免这些问题。

这还允许在实际类型具有相同名称方法的情况下轻松调用 trait 方法。例如,如果一个类型具有名为 borrow 的方法,并且还实现了 Borrow trait,那么当 Borrow 处于作用域内时,执行 value.borrow() 将调用类型的方法,但当 Borrow 处于作用域内时,将调用 Borrow::borrow

英文:

Rust has a rule that you cannot use trait methods unless the trait is in scope. If the trait is not in scope, you can still use the functions, just not with the postfix method syntax.

use chrono::Local;

fn main() {
    let d = Local::now().naive_local().date();
    println!("{}", chrono::Datelike::num_days_from_ce(&d));
}

But for nearly all cases, you'll bring the trait in scope and use the method syntax. Many of the standard library traits, such as Iterator, are imported automatically.

This rule exists for API reasons. Anyone can implement a trait on a foreign type, so if two of your dependencies each have a trait with a method with the same name, it creates an ambiguity. Dependencies don't have an ordering, so picking one over the other would be ambiguous. If this caused an error, it would mean a crate implementing a trait could be a breaking API change. Instead, rust requires the trait to be in scope, which avoids these problems.

This also allows easily calling trait methods when the actual type has a method of the same name. For example, if a type has a method called borrow and also implements the Borrow trait, doing value.borrow() will call the type's method, but when Borrow is in scope, it will call Borrow::borrow.

huangapple
  • 本文由 发表于 2023年3月31日 03:01:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75892035.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定