访问枚举变体的值
Access the value of an enum variant
我正在使用 arrayfire-rust crate.
对 Arrayfire 进行一些语言绑定
Arrayfire 具有类型结构 Array<T>
which represents a matrix. All acceptable types implement the HasAfEnum
特征。此特征有许多关联类型,其值对于实现此特征的类型是不同的。
由于我需要引用 Rwlock
中的数组以进行安全语言互操作,因此我定义了以下结构:
pub struct ExAfRef(pub RwLock<ExAfArray>);
impl ExAfRef {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
Self(RwLock::new(ExAfArray::new(slice, dim, dtype)))
}
pub fn value(&self) -> ExAfArray {
match self.0.try_read() {
Ok(refer) => (*refer),
Err(_) => unreachable!(),
}
}
}
它包含在结构中:
pub struct ExAf {
pub resource: ResourceArc<ExAfRef>,
}
impl ExAf {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
Self {
resource: ResourceArc::new(ExAfRef::new(slice, dim, dtype)),
}
}
// This function is broken
pub fn af_value<T: HasAfEnum>(&self) -> &Array<T> {
self.resource.value().value()
}
}
在以下枚举的帮助下:
pub enum ExAfArray {
U8(Array<u8>),
S32(Array<i32>),
S64(Array<i64>),
F32(Array<f32>),
F64(Array<f64>),
}
impl ExAfArray {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
let array = Array::new(slice, dim);
match dtype {
ExAfDType::U8 => ExAfArray::U8(array),
ExAfDType::S32 => ExAfArray::S32(array.cast::<i32>()),
ExAfDType::S64 => ExAfArray::S64(array.cast::<i64>()),
ExAfDType::F32 => ExAfArray::F32(array.cast::<f32>()),
ExAfDType::F64 => ExAfArray::F64(array.cast::<f64>()),
}
}
// This function is broken
pub fn value<T: HasAfEnum>(&self) -> &Array<T> {
// match self {
// ExAfArray::U8(array) => array,
// ExAfArray::S32(array) => array,
// ExAfArray::S64(array) => array,
// ExAfArray::F32(array) => array,
// ExAfArray::F64(array) => array,
// }
if let ExAfArray::U8(array) = self {
return array;
} else if let ExAfArray::S32(array) = self {
return array;
} else if let ExAfArray::S64(array) = self {
return array;
} else if let ExAfArray::F32(array) = self {
return array;
} else {
let ExAfArray::F64(array) = self;
return array;
}
}
pub fn get_type(&self) -> ExAfDType {
match self {
ExAfArray::U8(array) => ExAfDType::U8,
ExAfArray::S32(array) => ExAfDType::S32,
ExAfArray::S64(array) => ExAfDType::S64,
ExAfArray::F32(array) => ExAfDType::F32,
ExAfArray::F64(array) => ExAfDType::F64,
}
}
}
我使用了枚举,因为通用结构在我的语言互操作“框架”中不受支持,并且因为 HasAfEnum
特性具有关联类型(因此使用 dyn
的动态调度不可行(至少据我所知))。
这对于初始化新数组效果很好。
然而,当我需要对数组应用一些操作时,我需要能够访问枚举变量存储的值。但是我无法为函数编写类型签名来访问该值,因为动态调度不可用并且泛型太样板了。
由于所有变体都是元组,有什么方法可以使用内置枚举功能访问元组变体的值吗?
编辑:
我正在使用 rustler
简而言之,不,没有办法做你目前似乎在 Rust 中尝试做的事情。
您的函数已损坏,因为您正试图以与它们的工作方式正交的方式使用泛型。当在 Rust 中调用泛型函数时,调用者填写类型参数,而不是被调用者。但是,您的枚举在某种意义上“知道”具体数组类型是什么,因此只有它可以确定该类型参数应该是什么。如果这种不匹配阻碍了您的进步,这通常需要重新考虑您的代码结构。
这也解释了为什么没有 built-in 枚举方法来完成您想要做的事情。该方法将 运行 与您的 value
方法陷入相同的问题。当你想在 Rust 中检查枚举的内容时,你需要对其进行模式匹配。
至少有一种方法可以尝试实现您的目标,但我不会真正推荐它。使代码更接近可行的一个更改是将闭包传递到函数中以进行修改,(下面的语法目前不是有效的 Rust,但它理解了这个想法):
pub fn modify<'a, F>(&'a self, op: F)
where
F: for<T: HasAfEnum> FnOnce(&'a Array<T>)
{
// This looks repetitive, but the idea is that in each branch
// the type parameter T takes on the appropriate type for the variant
match self {
ExAfArray::U8(array) => op(array),
ExAfArray::S32(array) => op(array),
ExAfArray::S64(array) => op(array),
ExAfArray::F32(array) => op(array),
ExAfArray::F64(array) => op(array),
}
}
不幸的是,for<T> FnTrait(T)
语法尚不存在,我什至不确定是否有人建议添加它。这可以通过宏解决:
pub(crate) fn call_unary<F, T, U>(arg: T, f: F) -> U
where F: FnOnce(T) -> U {
f(arg)
}
macro_rules! modify {
($ex_af_array:expr, $op:expr) => {
match &$ex_af_array {
ExAfArray::U8(array) => call_unary(array, $op),
ExAfArray::S32(array) => call_unary(array, $op),
ExAfArray::S64(array) => call_unary(array, $op),
ExAfArray::F32(array) => call_unary(array, $op),
ExAfArray::F64(array) => call_unary(array, $op),
}
};
}
需要 call_unary
助手来确保类型推断正常工作。当 $op
的参数类型需要推断时,($op)(array)
将无法编译。
现在这个解决方案主要涵盖了 for<T> FnTrait(T)
将提供的功能,但它不是很干净的代码(尤其是在清理宏体之后),如果宏被误用,编译器错误会很糟糕。
我正在使用 arrayfire-rust crate.
对 Arrayfire 进行一些语言绑定Arrayfire 具有类型结构 Array<T>
which represents a matrix. All acceptable types implement the HasAfEnum
特征。此特征有许多关联类型,其值对于实现此特征的类型是不同的。
由于我需要引用 Rwlock
中的数组以进行安全语言互操作,因此我定义了以下结构:
pub struct ExAfRef(pub RwLock<ExAfArray>);
impl ExAfRef {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
Self(RwLock::new(ExAfArray::new(slice, dim, dtype)))
}
pub fn value(&self) -> ExAfArray {
match self.0.try_read() {
Ok(refer) => (*refer),
Err(_) => unreachable!(),
}
}
}
它包含在结构中:
pub struct ExAf {
pub resource: ResourceArc<ExAfRef>,
}
impl ExAf {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
Self {
resource: ResourceArc::new(ExAfRef::new(slice, dim, dtype)),
}
}
// This function is broken
pub fn af_value<T: HasAfEnum>(&self) -> &Array<T> {
self.resource.value().value()
}
}
在以下枚举的帮助下:
pub enum ExAfArray {
U8(Array<u8>),
S32(Array<i32>),
S64(Array<i64>),
F32(Array<f32>),
F64(Array<f64>),
}
impl ExAfArray {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
let array = Array::new(slice, dim);
match dtype {
ExAfDType::U8 => ExAfArray::U8(array),
ExAfDType::S32 => ExAfArray::S32(array.cast::<i32>()),
ExAfDType::S64 => ExAfArray::S64(array.cast::<i64>()),
ExAfDType::F32 => ExAfArray::F32(array.cast::<f32>()),
ExAfDType::F64 => ExAfArray::F64(array.cast::<f64>()),
}
}
// This function is broken
pub fn value<T: HasAfEnum>(&self) -> &Array<T> {
// match self {
// ExAfArray::U8(array) => array,
// ExAfArray::S32(array) => array,
// ExAfArray::S64(array) => array,
// ExAfArray::F32(array) => array,
// ExAfArray::F64(array) => array,
// }
if let ExAfArray::U8(array) = self {
return array;
} else if let ExAfArray::S32(array) = self {
return array;
} else if let ExAfArray::S64(array) = self {
return array;
} else if let ExAfArray::F32(array) = self {
return array;
} else {
let ExAfArray::F64(array) = self;
return array;
}
}
pub fn get_type(&self) -> ExAfDType {
match self {
ExAfArray::U8(array) => ExAfDType::U8,
ExAfArray::S32(array) => ExAfDType::S32,
ExAfArray::S64(array) => ExAfDType::S64,
ExAfArray::F32(array) => ExAfDType::F32,
ExAfArray::F64(array) => ExAfDType::F64,
}
}
}
我使用了枚举,因为通用结构在我的语言互操作“框架”中不受支持,并且因为 HasAfEnum
特性具有关联类型(因此使用 dyn
的动态调度不可行(至少据我所知))。
这对于初始化新数组效果很好。
然而,当我需要对数组应用一些操作时,我需要能够访问枚举变量存储的值。但是我无法为函数编写类型签名来访问该值,因为动态调度不可用并且泛型太样板了。
由于所有变体都是元组,有什么方法可以使用内置枚举功能访问元组变体的值吗?
编辑:
我正在使用 rustler
简而言之,不,没有办法做你目前似乎在 Rust 中尝试做的事情。
您的函数已损坏,因为您正试图以与它们的工作方式正交的方式使用泛型。当在 Rust 中调用泛型函数时,调用者填写类型参数,而不是被调用者。但是,您的枚举在某种意义上“知道”具体数组类型是什么,因此只有它可以确定该类型参数应该是什么。如果这种不匹配阻碍了您的进步,这通常需要重新考虑您的代码结构。
这也解释了为什么没有 built-in 枚举方法来完成您想要做的事情。该方法将 运行 与您的 value
方法陷入相同的问题。当你想在 Rust 中检查枚举的内容时,你需要对其进行模式匹配。
至少有一种方法可以尝试实现您的目标,但我不会真正推荐它。使代码更接近可行的一个更改是将闭包传递到函数中以进行修改,(下面的语法目前不是有效的 Rust,但它理解了这个想法):
pub fn modify<'a, F>(&'a self, op: F)
where
F: for<T: HasAfEnum> FnOnce(&'a Array<T>)
{
// This looks repetitive, but the idea is that in each branch
// the type parameter T takes on the appropriate type for the variant
match self {
ExAfArray::U8(array) => op(array),
ExAfArray::S32(array) => op(array),
ExAfArray::S64(array) => op(array),
ExAfArray::F32(array) => op(array),
ExAfArray::F64(array) => op(array),
}
}
不幸的是,for<T> FnTrait(T)
语法尚不存在,我什至不确定是否有人建议添加它。这可以通过宏解决:
pub(crate) fn call_unary<F, T, U>(arg: T, f: F) -> U
where F: FnOnce(T) -> U {
f(arg)
}
macro_rules! modify {
($ex_af_array:expr, $op:expr) => {
match &$ex_af_array {
ExAfArray::U8(array) => call_unary(array, $op),
ExAfArray::S32(array) => call_unary(array, $op),
ExAfArray::S64(array) => call_unary(array, $op),
ExAfArray::F32(array) => call_unary(array, $op),
ExAfArray::F64(array) => call_unary(array, $op),
}
};
}
需要 call_unary
助手来确保类型推断正常工作。当 $op
的参数类型需要推断时,($op)(array)
将无法编译。
现在这个解决方案主要涵盖了 for<T> FnTrait(T)
将提供的功能,但它不是很干净的代码(尤其是在清理宏体之后),如果宏被误用,编译器错误会很糟糕。