我是 Rust 的新手,对泛型类型的使用有点困惑。
考虑以下场景:
我可以像这样创建一个 Date 类型:
use chrono::prelude::*;
fn main() {
let date = Utc.ymd(2021, 1, 1);
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我创建一个函数foo来做类似的事情:
use chrono::prelude::*;
fn foo<Tz: TimeZone>(date: Date<Tz>) {
let other_date = Tz.ymd(2020, 1, 1);
}
fn main() {
let date = Utc.ymd(2021, 1, 1);
foo(date);
}
Run Code Online (Sandbox Code Playgroud)
我希望Tz被替换为Utc,并Tz.ymd等效于Utc.ymd,但事实并非如此:
error[E0423]: expected value, found type parameter `Tz`
--> src/main.rs:4:20
|
4 | let other_date = Tz.ymd(2020, 1, 1);
| ^^ not a value
Run Code Online (Sandbox Code Playgroud)
这让我认为它需要先实例化?但是为什么一开始就不需要呢?我在这里误解了什么?
chrono::offset::Utc是一个类似单元的 struct。这意味着它既是具有单个值的类型的名称,又是值本身的名称,例如()既是类型又是值。这是一个方便的功能,但有时会令人困惑。
在Utc.ymd(2021, 1, 1)您使用Utc作为值。只有值可以使用.syntax.¹然而,在foo,Tz是一个类型参数。它可以是实现 的任何类型TimeZone,因此您不能凭空创建type的值Tz。不过,你可以做的是采取timezone的Date<Tz>这是在通过了:
fn foo<Tz: TimeZone>(date: Date<Tz>) {
let other_date = date.timezone().ymd(2020, 1, 1);
}
Run Code Online (Sandbox Code Playgroud)
这会克隆Tz属于 的date并使用克隆创建other_date.
¹ 的完全限定版本Utc.ymd(2021, 1, 1)是<Utc as TimeZone>::ymd(&Utc, 2021, 1, 1)第一个Utc是类型 Utc,第二个是值 Utc。