Reputation: 114
I'm new to Rust, and a bit confused about the usage of generic types.
Consider the below scenario:
I can create a Date type like so:
use chrono::prelude::*;
fn main() {
let date = Utc.ymd(2021, 1, 1);
}
Now if I create a function foo
to do something similar:
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);
}
I expected Tz
to be substituted by Utc
, and Tz.ymd
to be equivalent to Utc.ymd
, but it's not so:
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
Which makes me think it needs to be instantiated first? But how come that wasn't needed in the first place? What am I misunderstanding here?
Upvotes: 2
Views: 290
Reputation: 27895
chrono::offset::Utc
is a unit-like struct. This means that it is both the name of a type with a single value and the name of the value itself, like ()
is both a type and a value. This is a convenience feature but it can sometimes be confusing.
In Utc.ymd(2021, 1, 1)
you are using Utc
as a value. Only values can use .
syntax.¹ However, in foo
, Tz
is a type parameter. It could be any type that implements TimeZone
, so you can't create a value of type Tz
out of thin air. However, what you can do is take the timezone
of the Date<Tz>
which was passed in:
fn foo<Tz: TimeZone>(date: Date<Tz>) {
let other_date = date.timezone().ymd(2020, 1, 1);
}
This clones the Tz
that is part of date
and uses the clone to create other_date
.
¹ The fully-qualified version of Utc.ymd(2021, 1, 1)
is <Utc as TimeZone>::ymd(&Utc, 2021, 1, 1)
where the first Utc
is the type Utc
and the second one is the value Utc
.
Upvotes: 5