我如何在Rust中实现自定义类型的abs函数?



我目前正在使用Rust编写一个数字代码。所以我自己创建了一个类型。这个特性是一种允许rust_narray同时在f64和f32上执行计算的数据方式。为了使其多线程,我们在trait的边界中添加了Sync和Send。如何在自己的类型中实现在其他整数类型中找到的函数?

use ndarray_linalg::lapack::Lapack;
use ndarray_linalg::types::Scalar;
use ndarray_linalg::rand_distr::Float;
use std::marker::{Sync, Send};
pub trait Type: Lapack + Scalar + Float + Sync + Send {}
impl Type for f32 {}
impl Type for f64 {}

我想写我自己的函数来找到这个类型的绝对值。我该如何实现它?我做了如下所示的实现,得到了以下错误:

impl Type {
pub fn abs(&self) -> Self {
if self.0 > 0. {self.0}
else {-1. * self.0}
}
}

我收到以下错误。考虑到我收到的错误,我在Type中使用的trait边界似乎有问题。我也试过在边界中包含ParticalOrd和ParticalEq,但收到了同样的错误。

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>
|
::: src/traits.rs:7:11
|
7   | pub trait Type: Lapack + Scalar + Float + Sync + Send {}
|           ------- this trait cannot be made into an object...
--> /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_distr-0.2.2/src/utils.rs:24:33
|
24  | pub trait Float: Copy + Sized + cmp::PartialOrd
|                                 ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
25  |     + ops::Neg<Output = Self>
26  |     + ops::Add<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
27  |     + ops::Sub<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
28  |     + ops::Mul<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
29  |     + ops::Div<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
30  |     + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign
|       ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
|       |                |                |
|       |                |                ...because it uses `Self` as a type parameter
|       |                ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
|
::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/cauchy-0.2.2/src/lib.rs:44:7
|
44  |     + Sum
|       ^^^ ...because it uses `Self` as a type parameter
45  |     + Product
|       ^^^^^^^ ...because it uses `Self` as a type parameter
|
::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/lib.rs:67:41
|
67  | pub trait Num: PartialEq + Zero + One + NumOps {
|                ^^^^^^^^^                ^^^^^^ ...because it uses `Self` as a type parameter
|                |
|                ...because it uses `Self` as a type parameter
...
149 | pub trait NumAssign: Num + NumAssignOps {}
|                            ^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
|
::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/identities.rs:12:25
|
12  | pub trait Zero: Sized + Add<Self, Output = Self> {
|                         ^^^^^^^^^^^^^^^^^^^^^^^^
|                         |         |
|                         |         ...because it uses `Self` as a type parameter
|                         ...because it uses `Self` as a type parameter
...
90  | pub trait One: Sized + Mul<Self, Output = Self> {
|                        ^^^^^^^^^^^^^^^^^^^^^^^^
|                        |         |
|                        |         ...because it uses `Self` as a type parameter
|                        ...because it uses `Self` as a type parameter
error[E0038]: the trait `Type` cannot be made into an object
--> src/traits.rs:13:6

13  | impl Type {
|      ^^^^^^^ `Type` cannot be made into an object
|
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>
|
::: src/traits.rs:7:11
|
7   | pub trait Type: Lapack + Scalar + Float + Sync + Send {}
|           ------- this trait cannot be made into an object...
--> /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/rand_distr-0.2.2/src/utils.rs:24:33
|
24  | pub trait Float: Copy + Sized + cmp::PartialOrd
|                                 ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
25  |     + ops::Neg<Output = Self>
26  |     + ops::Add<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
27  |     + ops::Sub<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
28  |     + ops::Mul<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
29  |     + ops::Div<Output = Self>
|       ^^^^^^^^^^^^^^^^^^^^^^^
|       |        |
|       |        ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
30  |     + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign
|       ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
|       |                |                |
|       |                |                ...because it uses `Self` as a type parameter
|       |                ...because it uses `Self` as a type parameter
|       ...because it uses `Self` as a type parameter
|
::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/cauchy-0.2.2/src/lib.rs:44:7
|
44  |     + Sum
|       ^^^ ...because it uses `Self` as a type parameter
45  |     + Product
|       ^^^^^^^ ...because it uses `Self` as a type parameter
|
::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/lib.rs:67:41
|
67  | pub trait Num: PartialEq + Zero + One + NumOps {
|                ^^^^^^^^^                ^^^^^^ ...because it uses `Self` as a type parameter
|                |
|                ...because it uses `Self` as a type parameter
...
149 | pub trait NumAssign: Num + NumAssignOps {}
|                            ^^^^^^^^^^^^ ...because it uses `Self` as a type parameter
|
::: /Users/~~/.cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/identities.rs:12:25
|
12  | pub trait Zero: Sized + Add<Self, Output = Self> {
|                         ^^^^^^^^^^^^^^^^^^^^^^^^
|                         |         |
|                         |         ...because it uses `Self` as a type parameter
|                         ...because it uses `Self` as a type parameter
...
90  | pub trait One: Sized + Mul<Self, Output = Self> {
|                        ^^^^^^^^^^^^^^^^^^^^^^^^
|                        |         |
|                        |         ...because it uses `Self` as a type parameter
|                        ...because it uses `Self` as a type parameter

您的Type实际上不是数据类型,而是特征。当你为一个特质写一个impl时,你实际上是在为那个特质的dyn对象版本写它,这通常不是你想要的。事实上,你可能会得到这样的警告:

warning: trait objects without an explicit `dyn` are deprecated

其余的错误出现是因为你的trait需求不是dyn-object安全的。

你可能需要的是trait中的一个简单函数:

pub trait Type: Lapack + Scalar + Float + Sync + Send {
fn abs(&self) -> Self;
}
impl Type for f32 {
fn abs(&self) -> Self {
Self::abs(*self)
}
}
impl Type for f64 {
fn abs(&self) -> Self {
Self::abs(*self)
}
}

是的,您必须为实现Type的每个类型重复代码,但对于这种情况,这几乎没有什么不便。

如果有很多类型和很多函数可以使用宏,这就是大多数库所做的。

最新更新