[英]Cast a struct with a generic type parameter to a specific type
注意:今天早些时候我问了一个类似的问题,但这个问题有很大的不同,所以我把它作为一个单独的问题发布。
如果我有两个(或更多)结构:
struct A {...}
struct B {...}
和一个通用函数fn f<T>(param: Vec<T>)
我通过传递A
或B
的向量(或其他类型的)调用它,该函数中有没有办法有这样的东西(伪代码):
if param is Vec<A> {
// do something with "param as Vec<A>", like this:
let a: Vec<A> = (Vec<A>) param;
// ...
}
通常在 OOP 语言中,我基本上可以检查向量参数的类型或其元素之一(假设向量不为空)并转换参数。
在 Rust 中,是否有一种简单而直接的方法来实现这一点,而无需牺牲性能,也无需更改函数签名或在函数外部编写任何代码(因此没有枚举包装器、特征、动态/运行时“魔术” “, 等等。)。
如果您能够约束T: 'static
您仍然可以使用链接问题中所示的Any
方法
use std::any::Any;
struct A {}
struct B {}
fn f<T: 'static>(param: Vec<T>) {
if let Some(_param_a) = (¶m as &dyn Any).downcast_ref::<Vec<A>>() {
println!("I am a Vec<A>");
}
else {
println!("I am something else");
}
}
fn main() {
f(Vec::<A>::new());
f(Vec::<B>::new());
}
这没有任何运行时成本。
你正在寻找的东西在当前的 Rust 中还没有完全可用,但一旦专业化功能登陆就会可用。 使用专业化并在当前每晚可测试,您的函数将如下所示:
#![feature(min_specialization)]
struct A {}
struct B {}
fn f<T>(param: Vec<T>) {
trait Detect {
fn detect(&self);
}
impl<T> Detect for Vec<T> {
default fn detect(&self) {
println!("I am something else");
}
}
impl Detect for Vec<A> {
fn detect(&self) {
println!("I am a Vec<A>");
}
}
param.detect();
// ...
}
fn main() {
f(Vec::<A>::new());
f(Vec::<B>::new());
}
TL; 博士
使用特征来表示T
应该具有的行为:
struct Answer {}
struct Question {}
trait Summarizable { fn summarize(&self); }
impl Summarizable for Answer {
fn summarize(&self) { println!("I'm an answer"); }
}
impl Summarizable for Question {
fn summarize(&self) { println!("I'm a question"); }
}
fn main() {
let posts: Vec<&dyn Summarizable> = vec![&Answer {}, &Question {}];
for post in posts {
post.summarize();
}
}
我相信 Rust 与其他语言有很大的不同,至少在 OOP 方面如此,所以我们在其他语言中的常见反应最好被抛在后面。 我从 Rust 中了解到的部分精神是,我们几乎从不以“我的价值观实际包含什么”模式运作。
Rust 并没有尝试去猜测值的类型,而是精心制作了构造,将这种猜测从我们的手中转移到代码的结构中。
例如,让我们考虑match
构造,以Book 中的示例为例:
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
这是非常简单的,但这里的关键思想是:在比赛的所有武器,我们确切地知道什么类型我们在行动上。 我相信这些特殊的信息可以帮助我解决手头的问题,即根据值的类型尝试不同的行为,因为它提示我挑战我编写的依赖于这种未知状态的代码值。
我没有理由在想知道我的价值观是什么时编码,因为语言结构允许我在我知道的上下文中进行编写。 在这种情况下,它通过从手动类型检查中移动代码来工作:
fn main() {
let posts: Vec<&dyn Summarizable> = vec![&Answer {}, &Question {}];
for post in posts {
// this is pseudocode
if typeof post == Answer {
println!("I'm an answer");
}
if typeof post == Question {
println!("I'm a question");
}
}
}
特定于对应于该类型的行为的代码:
impl Summarizable for Answer {
fn summarize(&self) { println!("I'm an answer"); }
}
impl Summarizable for Question {
fn summarize(&self) { println!("I'm a question"); }
}
在使实际的主要功能方式更清楚实际应该发生什么的同时,也就是总结帖子,不要怀疑它们是什么:
fn main() {
let posts: Vec<&dyn Summarizable> = vec![&Answer {}, &Question {}];
for post in posts {
post.summarize();
}
}
ps 我忽略了你问题的“无特征”部分,因为我觉得它不合理。 如果你想写其他语言,他们可以! 但是 Rust 中的 trait 是解决一般“根据值的类型采取不同行动”问题的惯用方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.