英文:
Define variable of type TimeZone
问题
以下是您要求的代码部分的翻译:
// 原始代码
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate};
use arrow2::temporal_conversions::parse_offset;
fn my_func(tz: &str) -> () {
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
match parse_offset(&tz) {
Ok(time_zone) => {
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
},
Err(_) => match tz.parse::<Tz>() {
Ok(time_zone) => {
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
}
Err(error) => panic!("Problem opening the file: {:?}", error)
},
};
}
fn main() {
let time_zone = "Asia/Seoul";
my_func(&time_zone);
}
// 重构后的代码
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate};
use arrow2::temporal_conversions::parse_offset;
fn my_func(tz: &str) -> () {
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
let parsed_time_zone: Tz = match parse_offset(&tz) {
Ok(time_zone) => {
time_zone
},
Err(_) => match tz.parse::<Tz>() {
Ok(time_zone) => {
time_zone
}
Err(error) => panic!("Problem opening the file: {:?}", error)
},
};
println!("converted: {:?}", parsed_time_zone.from_utc_datetime(&ndt));
}
fn main() {
let time_zone = "Asia/Seoul";
my_func(&time_zone);
}
希望这对您有所帮助。如果您有其他问题,请随时提问。
英文:
The following compiles and runs fine:
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate};
use arrow2::temporal_conversions::parse_offset;
fn my_func(tz: &str) -> (){
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
match parse_offset(&tz) {
Ok(time_zone) => {
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
},
Err(_) => match tz.parse::<Tz>() {
Ok(time_zone) => {
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
}
Err(error) => panic!("Problem opening the file: {:?}", error)
},
};
}
fn main() {
let time_zone = "Asia/Seoul";
my_func(&time_zone);
}
Noticed though that I'm doing
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
twice.
I've tried refactoring to
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate};
use arrow2::temporal_conversions::parse_offset;
fn my_func(tz: &str) -> (){
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
let parsed_time_zone: TimeZone = match parse_offset(&tz) {
Ok(time_zone) => {
time_zone
},
Err(_) => match tz.parse::<Tz>() {
Ok(time_zone) => {
time_zone
}
Err(error) => panic!("Problem opening the file: {:?}", error)
},
};
println!("converted: {:?}", parsed_time_zone.from_utc_datetime(&ndt));
}
fn main() {
let time_zone = "Asia/Seoul";
my_func(&time_zone);
}
and get a long error:
error[E0782]: trait objects must include the `dyn` keyword
--> src/main.rs:7:27
|
7 | let parsed_time_zone: TimeZone = match parse_offset(&tz) {
| ^^^^^^^^
|
help: add `dyn` keyword before this trait
|
7 | let parsed_time_zone: dyn TimeZone = match parse_offset(&tz) {
| +++
error[E0191]: the value of the associated type `Offset` (from trait `TimeZone`) must be specified
--> src/main.rs:7:27
|
7 | let parsed_time_zone: TimeZone = match parse_offset(&tz) {
| ^^^^^^^^ help: specify the associated type: `TimeZone<Offset = Type>`
error[E0038]: the trait `TimeZone` cannot be made into an object
--> src/main.rs:7:27
|
7 | let parsed_time_zone: TimeZone = match parse_offset(&tz) {
| ^^^^^^^^ `TimeZone` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
error[E0308]: mismatched types
--> src/main.rs:9:13
|
9 | time_zone
| ^^^^^^^^^ expected trait object `dyn TimeZone`, found struct `FixedOffset`
|
= note: expected trait object `dyn TimeZone`
found struct `FixedOffset`
error[E0308]: mismatched types
--> src/main.rs:13:17
|
13 | time_zone
| ^^^^^^^^^ expected trait object `dyn TimeZone`, found enum `Tz`
|
= note: expected trait object `dyn TimeZone`
found enum `Tz`
error: the `from_utc_datetime` method cannot be invoked on a trait object
--> src/main.rs:18:50
|
18 | println!("converted: {:?}", parsed_time_zone.from_utc_datetime(&ndt));
| ^^^^^^^^^^^^^^^^^
|
::: /home/marcogorelli/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.23/src/offset/mod.rs:205:21
|
205 | pub trait TimeZone: Sized + Clone {
| ----- this has a `Sized` requirement
Some errors have detailed explanations: E0038, E0191, E0308, E0782.
For more information about an error, try `rustc --explain E0038`.
error: could not compile `tmp` due to 6 previous errors
I've tried the suggestion to do
let parsed_time_zone: dyn TimeZone = match parse_offset(&tz) {
but then it still errors with
error[E0191]: the value of the associated type `Offset` (from trait `TimeZone`) must be specified
--> src/main.rs:7:31
|
7 | let parsed_time_zone: dyn TimeZone = match parse_offset(&tz) {
| ^^^^^^^^ help: specify the associated type: `TimeZone<Offset = Type>`
How can I just parse tz
as TimeZone
, without specified whether it's Tz
or FixedOffset
, and then use it in the rest of the function?
答案1
得分: 1
你无法轻松重构这部分。Rust 是强类型语言,而你的两个 time_zone
变量不是相同的类型。一个是 chrono::FixedOffset
,另一个是 chrono_tz::Tz
。
如果你确实想将它们都存储在同一个变量中,你有两种可能性:
- 特质对象引用 (
&dyn TimeZone
) - 包装的特质对象 (
Box<dyn TimeZone>
).
dyn Timezone
本身不能直接成为变量的类型。它没有已知的大小,因为它可以是任何实际大小的类型。因此,你需要使用上述其中一种间接方法。
然而,对于你的情况来说,这两种方法都不太理想:
&dyn TimeZone
不起作用,因为必须有某个拥有实际对象的人。你不能返回对内部范围变量的引用,因为它比引用更早被丢弃。Box<dyn TimeZone>
可以工作,没有问题,但它会引入开销:它会在堆上分配实际对象的空间。正如前面所描述的,dyn
对象没有已知的大小。因此,使用Box
,实际对象被移到堆上,在堆栈上的是Box
对象,它有已知的大小。
所以我建议的做法是:不要担心。你在这里的代码重复非常小。我不认为值得麻烦。
我在回答这个问题后注意到的进一步细节:
TimeZone
是: Sized
,这意味着它不是对象安全,并且完全不允许使用dyn TimeZone
。因此,甚至Box<dyn TimeZone>
也不会起作用。
英文:
You can't refactor this easily. Rust is strongly typed, and your two time_zone
variables aren't the same type. One is chrono::FixedOffset
, the other is chrono_tz::Tz
.
If you do want to store both of them in the same variable, you have two possibilities:
- trait object references (
&dyn TimeZone
) - Boxed trait objects (
Box<dyn TimeZone
).
dyn Timezone
itself cannot directly be the type of a variable. It doesn't have a known size, because it could be any actual type of any size. Therefore you need one of the indirections above.
Both are non-ideal for your case though:
&dyn TimeZone
won't work because someone has to own the actual object. You can't return a reference to a variable of an inner scope, as it gets dropped earlier than the reference does.Box<dyn TimeZone>
would work, no problem, but it introduces overhead: It will cause a heap allocation where the actual object will be put. The reason, as described earlier, is that adyn
object doesn't have a known size. Therefore, withBox
, the actual object gets moved to the heap, and on the stack is theBox
object, which has a known size.
So what I would do is: don't worry. The code duplication you have here is really minimal. I don't think it's worth the trouble.
Further detail I noticed after I wrote this answer:
- TimeZone is
: Sized
, which means it isn't object safe anddyn TimeZone
is disallowed entirely. So not evenBox<dyn TimeZone>
would work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论