简体   繁体   English

将具有泛型类型参数的结构转换为特定类型

[英]Cast a struct with a generic type parameter to a specific type

Note: Earlier today I asked a similar question , but this one has a significant difference, so I am posting it as a separate question.注意:今天早些时候我问了一个类似的问题,但这个问题有很大的不同,所以我把它作为一个单独的问题发布。

If I have two (or more) structs:如果我有两个(或更多)结构:

struct A {...}
struct B {...}

and a generic function fn f<T>(param: Vec<T>) that I call with passing a vector of A or B (or some other type for that matter), is there a way in that function to have something like this (pseudo code):和一个通用函数fn f<T>(param: Vec<T>)我通过传递AB的向量(或其他类型的)调用它,该函数中有没有办法有这样的东西(伪代码):

if param is Vec<A> {
    // do something with "param as Vec<A>", like this:
    let a: Vec<A> = (Vec<A>) param;
    // ...
}

Typically in OOP languages I could basically check the type of the vector parameter or one of its elements (given the vector is not empty) and cast the parameter.通常在 OOP 语言中,我基本上可以检查向量参数的类型或其元素之一(假设向量不为空)并转换参数。

In Rust, is there a simple and direct way to achieve that, w/o sacrificing performance and w/o the need to change the function signature or write any code outside the function (so no enum wrappers, traits, dyn/runtime "magic", etc.).在 Rust 中,是否有一种简单直接的方法来实现这一点,而无需牺牲性能,也无需更改函数签名或在函数外部编写任何代码(因此没有枚举包装器、特征、动态/运行时“魔术” “, 等等。)。

You can still use the Any approach as shown in the linked question if you are able to constrain T: 'static如果您能够约束T: 'static您仍然可以使用链接问题中所示的Any方法

use std::any::Any;

struct A {}
struct B {}

fn f<T: 'static>(param: Vec<T>) {
    if let Some(_param_a) = (&param 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());
}

This does not have any runtime cost.这没有任何运行时成本。

What you're looking for is not yet quite available in current Rust, but will become available once the specialization feature lands.你正在寻找的东西在当前的 Rust 中还没有完全可用,但一旦专业化功能登陆就会可用。 Using specialization, and testable on current nightly, your function would look like this:使用专业化并在当前每晚可测试,您的函数将如下所示:

#![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());
}

Playground 操场

TL;DR TL; 博士

Use traits to represent what behaviour T is supposed to have:使用特征来表示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();
    }
}

I believe Rust to be sufficiently different from other languages, at the very least OOP-wise, so that usual reflexes we have in other languages are best left behind.我相信 Rust 与其他语言有很大的不同,至少在 OOP 方面如此,所以我们在其他语言中的常见反应最好被抛在后面。 Part of the spirit I understand from Rust is that we almost never operate in a "what are my values actually containing" mode.我从 Rust 中了解到的部分精神是,我们几乎从不以“我的价值观实际包含什么”模式运作。

Rather than try and divine the type of a value, Rust have beautifully crafted constructs to lift that guessing out of our hands and into the very structure of the code. Rust 并没有尝试去猜测值的类型,而是精心制作了构造,将这种猜测从我们的手中转移到代码的结构中。

For instance, let's consider the match construct, with example from the Book :例如,让我们考虑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,
    }
}

It is extremely simple, but the key idea here is that in all arms of the match, we know exactly what type we are acting on .非常简单的,但这里的关键思想是:在比赛的所有武器,我们确切地知道什么类型我们在行动上 And I believe this particular bit of information helps me solve the kind of problem at hand here, that is to try and act differently depending on the type of a value, because it prompts me to challenge the code I write that depends on such unknown state of values.我相信这些特殊的信息可以帮助我解决手头的问题,即根据值的类型尝试不同的行为,因为它提示我挑战我编写的依赖于这种未知状态的代码值。

I have no reason to code while wondering what are my values because the language constructs allow me to write in a context where I know.我没有理由在想知道我的价值观是什么时编码,因为语言结构允许我在我知道的上下文中进行编写。 In this case, it works by moving the code from a manual type checking :在这种情况下,它通过从手动类型检查中移动代码来工作:

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");
        }
    }
}

To code that is specific to the behaviour that corresponds to that type:特定于对应于该类型的行为的代码:

impl Summarizable for Answer {
    fn summarize(&self) { println!("I'm an answer"); }
}
impl Summarizable for Question {
    fn summarize(&self) { println!("I'm a question"); }
}

While making the actual main function way clearer in terms of what is actually supposed to happen, that is to summarize the posts, not wonder about what they are:在使实际的主要功能方式更清楚实际应该发生什么的同时,也就是总结帖子,不要怀疑它们是什么:

fn main() {
    let posts: Vec<&dyn Summarizable> = vec![&Answer {}, &Question {}];
    for post in posts {
        post.summarize();
    }
}

ps I ignored the "no traits" part of your question because I find it unreasonnable. ps 我忽略了你问题的“无特征”部分,因为我觉得它不合理。 If one wants to write other languages, they can!如果你想写其他语言,他们可以! But traits in Rust are an idiomatic way to solve the general "acting differently based on the type of a value" problem.但是 Rust 中的 trait 是解决一般“根据值的类型采取不同行动”问题的惯用方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM