将具有泛型类型参数的结构转换为特定类型
Cast a struct with a generic type parameter to a specific type
注意:今天早些时候我问了一个similar question,但是这个有很大的不同,所以我把它作为一个单独的问题发布。
如果我有两个(或更多)结构:
struct A {...}
struct B {...}
和我通过传递 A
或 B
(或与此相关的其他类型)的向量调用的通用函数 fn f<T>(param: Vec<T>)
,该函数中有没有办法有这样的东西(伪代码):
if param is Vec<A> {
// do something with "param as Vec<A>", like this:
let a: Vec<A> = (Vec<A>) param;
// ...
}
通常在 OOP 语言中,我基本上可以检查向量参数或其元素之一的类型(假定向量不为空)并转换参数。
在 Rust 中,是否有 简单 和 直接 方法来实现,w/o 牺牲性能和 w/o 需要更改函数签名或在函数外编写任何代码(因此没有枚举包装器、特征、dyn/runtime“魔法”等)。
如果您能够约束 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());
}
它甚至可以通过提供类似“演员表”的特征使其变得通用:
trait Cast<To> {
fn with_cast(&self, fun: impl FnOnce(Option<&To>));
}
impl<T, To> Cast<To> for T {
default fn with_cast(&self, fun: impl FnOnce(Option<&To>)) {
fun(None)
}
}
使用 Cast
,f
函数将如下所示:
fn f<T>(param: Vec<T>) {
impl Cast<Vec<A>> for Vec<A> {
fn with_cast(&self, fun: impl FnOnce(Option<&Self>)) {
fun(Some(self));
}
}
param.with_cast(|val: Option<&Vec<A>>| {
if let Some(_param_a) = val {
// here I can access fields of param_a
println!("I'm a Vec<A>");
} else {
println!("I'm something else");
}
});
// ...
}
注意:今天早些时候我问了一个similar question,但是这个有很大的不同,所以我把它作为一个单独的问题发布。
如果我有两个(或更多)结构:
struct A {...}
struct B {...}
和我通过传递 A
或 B
(或与此相关的其他类型)的向量调用的通用函数 fn f<T>(param: Vec<T>)
,该函数中有没有办法有这样的东西(伪代码):
if param is Vec<A> {
// do something with "param as Vec<A>", like this:
let a: Vec<A> = (Vec<A>) param;
// ...
}
通常在 OOP 语言中,我基本上可以检查向量参数或其元素之一的类型(假定向量不为空)并转换参数。
在 Rust 中,是否有 简单 和 直接 方法来实现,w/o 牺牲性能和 w/o 需要更改函数签名或在函数外编写任何代码(因此没有枚举包装器、特征、dyn/runtime“魔法”等)。
如果您能够约束 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());
}
它甚至可以通过提供类似“演员表”的特征使其变得通用:
trait Cast<To> {
fn with_cast(&self, fun: impl FnOnce(Option<&To>));
}
impl<T, To> Cast<To> for T {
default fn with_cast(&self, fun: impl FnOnce(Option<&To>)) {
fun(None)
}
}
使用 Cast
,f
函数将如下所示:
fn f<T>(param: Vec<T>) {
impl Cast<Vec<A>> for Vec<A> {
fn with_cast(&self, fun: impl FnOnce(Option<&Self>)) {
fun(Some(self));
}
}
param.with_cast(|val: Option<&Vec<A>>| {
if let Some(_param_a) = val {
// here I can access fields of param_a
println!("I'm a Vec<A>");
} else {
println!("I'm something else");
}
});
// ...
}