如何在 trait bound 中指定 `std::ops::Mul` 的预期结果?
How do I specify the expected result of a `std::ops::Mul` in a trait bound?
我有:
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Hilbert: Add + Sub + Mul + Div + Neg + Mul<f64> + Div<f64> + Sized {
fn dot(&self, other: &Self) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert>(x: T) -> f64 {
return (x * 2.0).dot(x);
}
...产生:
error[E0599]: no method named `dot` found for type `<T as std::ops::Mul<f64>>::Output` in the current scope
--> src/main.rs:9:22
|
9 | return (x * 2.0).dot(x);
| ^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `dot`, perhaps you need to implement it:
candidate #1: `Hilbert`
我将其解释为 Rust 无法保证具有特征 Hilbert
的类型 T
具有 std::ops::Mul
的 ::Output
类型的实现等于T
(一个Hilbert
)。
但我知道(和/或希望要求)所有 Hilbert
都是这种情况,因此可以编写像 g()
这样的函数。
我想为 Hilbert
:
实施 std::ops::Mul::Output
impl<T: Hilbert> Mul<f64> for T {
type Output = T;
}
...但这同时存在的问题是 (a) 我不能 "partially implement" 一个特征,并且将被迫为所有 Mul::mul()
生成函数的通用实现 Hilberts
,但Mul::mul()
的实际实现将取决于Hilbert
的具体实现;并且(b)似乎我根本不允许写这个特征:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter
--> src/main.rs:12:1
|
12 | / impl<T: Hilbert> Mul<f64> for T {
13 | | type Output = T;
14 | | }
| |_^
我如何说服 Rust Hilbert
* f64
-> Hilbert
必须成立?
How do I persuade Rust that Hilbert * f64
-> Hilbert
must hold?
你添加了一个特征绑定<T as Mul<f64>>::Output: Hilbert
。但是,这样做会揭示您设计中的更多问题:
Hilbert.dot()
将第二个参数作为参考,而不是按值。但是将相关行更改为 (x * 2.0).dot(&x)
会导致另一个错误:"expected associated type, found type parameter".
- 这是因为您将
dot
定义为取 Self
,但您可能希望乘以 Hilbert
的不同实现。 dot
需要通用:fn dot<H: Hilbert>(&self, other: &H) -> f64;
- 最后,借用检查器命中:
(x * 2.0).dot(&x)
不会让您使用 x
两次,因为 mul
按值获取其参数。您将必须添加一个绑定 Mul<&'a Self>
才能传递引用(这会用生命周期参数感染您的 API )或使 x
可克隆(我认为可复制不会申请)。
在这个工作(?)可编译代码中应用以上所有结果:
pub trait Hilbert: Add + Sub + Mul + Div + Neg + Mul<f64> + Div<f64> + Sized {
fn dot<H: Hilbert>(&self, other: &H) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert + Clone>(x: T) -> f64
where
<T as Mul<f64>>::Output: Hilbert,
{
(x.clone() * 2.0).dot(&x)
}
如果Hilbert.dot
不应该是通用的,因为Hilbert
的不同实现不需要交互,代码可以稍微简单一点(在trait bounds方面):
pub trait Hilbert:
Add + Sub + Mul + Div + Neg + Mul<f64, Output = Self> + Div<f64, Output = Self> + Sized
{
fn dot(&self, other: &Self) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert + Clone>(x: T) -> f64 {
(x.clone() * 2.0).dot(&x)
}
然而,根据我对希尔伯特变换的了解,后一种情况似乎不太可能有用。
我有:
use std::ops::{Add, Div, Mul, Neg, Sub};
pub trait Hilbert: Add + Sub + Mul + Div + Neg + Mul<f64> + Div<f64> + Sized {
fn dot(&self, other: &Self) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert>(x: T) -> f64 {
return (x * 2.0).dot(x);
}
...产生:
error[E0599]: no method named `dot` found for type `<T as std::ops::Mul<f64>>::Output` in the current scope
--> src/main.rs:9:22
|
9 | return (x * 2.0).dot(x);
| ^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `dot`, perhaps you need to implement it:
candidate #1: `Hilbert`
我将其解释为 Rust 无法保证具有特征 Hilbert
的类型 T
具有 std::ops::Mul
的 ::Output
类型的实现等于T
(一个Hilbert
)。
但我知道(和/或希望要求)所有 Hilbert
都是这种情况,因此可以编写像 g()
这样的函数。
我想为 Hilbert
:
std::ops::Mul::Output
impl<T: Hilbert> Mul<f64> for T {
type Output = T;
}
...但这同时存在的问题是 (a) 我不能 "partially implement" 一个特征,并且将被迫为所有 Mul::mul()
生成函数的通用实现 Hilberts
,但Mul::mul()
的实际实现将取决于Hilbert
的具体实现;并且(b)似乎我根本不允许写这个特征:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter
--> src/main.rs:12:1
|
12 | / impl<T: Hilbert> Mul<f64> for T {
13 | | type Output = T;
14 | | }
| |_^
我如何说服 Rust Hilbert
* f64
-> Hilbert
必须成立?
How do I persuade Rust that
Hilbert * f64
->Hilbert
must hold?
你添加了一个特征绑定<T as Mul<f64>>::Output: Hilbert
。但是,这样做会揭示您设计中的更多问题:
Hilbert.dot()
将第二个参数作为参考,而不是按值。但是将相关行更改为(x * 2.0).dot(&x)
会导致另一个错误:"expected associated type, found type parameter".- 这是因为您将
dot
定义为取Self
,但您可能希望乘以Hilbert
的不同实现。dot
需要通用:fn dot<H: Hilbert>(&self, other: &H) -> f64;
- 最后,借用检查器命中:
(x * 2.0).dot(&x)
不会让您使用x
两次,因为mul
按值获取其参数。您将必须添加一个绑定Mul<&'a Self>
才能传递引用(这会用生命周期参数感染您的 API )或使x
可克隆(我认为可复制不会申请)。
在这个工作(?)可编译代码中应用以上所有结果:
pub trait Hilbert: Add + Sub + Mul + Div + Neg + Mul<f64> + Div<f64> + Sized {
fn dot<H: Hilbert>(&self, other: &H) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert + Clone>(x: T) -> f64
where
<T as Mul<f64>>::Output: Hilbert,
{
(x.clone() * 2.0).dot(&x)
}
如果Hilbert.dot
不应该是通用的,因为Hilbert
的不同实现不需要交互,代码可以稍微简单一点(在trait bounds方面):
pub trait Hilbert:
Add + Sub + Mul + Div + Neg + Mul<f64, Output = Self> + Div<f64, Output = Self> + Sized
{
fn dot(&self, other: &Self) -> f64;
fn magnitude(&self) -> f64;
}
fn g<T: Hilbert + Clone>(x: T) -> f64 {
(x.clone() * 2.0).dot(&x)
}
然而,根据我对希尔伯特变换的了解,后一种情况似乎不太可能有用。