问题描述
我刚接触锈,但是对于我正在从事的实践项目,我想实现一个像API这样的React useMemo,我想如果闭包的类型是静态的,并且捕获变量存储在某个地方,我应该不能检查是否相等?
类似的东西:
let cached = scope.use_memo(move || {
complicated_computation(captured_variable)
});
其中use_memo类似于
pub fn use_memo<F: Fn() -> T + PartialEq + 'static,T: Clone + 'static>(&mut self,factory: F) -> &T
在代码中的什么地方,我可以将工厂与以前存储的工厂函数进行比较,并确定是否需要重新运行工厂。
显然这是行不通的,因为闭包没有实现PartialEq
,但是我想知道是否有办法实现它。
解决方法
我认为这是不可能的:Rust闭包在某种程度上是匿名类型,因此您无法在其上实现特征。而且,如果您使用更多的“显式”闭包,则可以在其中手工构建环境并传递一个简单的函数指针:
fn use_memo<T: PartialEq>(&mut self,env: T,func: fn(T))
您可以将它们进行比较:
fn main(){
let a: fn(u8) -> u8 = |a: u8| a;
let b: fn(u8) -> u8 = |a: u8| a % 2;
println!("{}",a == b) -> false
}
但是您会遇到一个问题,即不同的回调将具有不同的环境,因此类型将不匹配,并且可能仍然无法比较它们。
,我在防锈方面也很新,但是一个想法可能是拥有定义方法FactoryIdentifiable
的自定义特征get_identifier
。
然后,您可以使用运算符重载并为此特征实现PartialEq
,并修改闭包的类型签名以也需要该特征。
pub fn use_memo<F: Fn() -> T + FactoryIdentifiable,T: Clone + 'static>(&mut self,factory: F) -> &T
,
不。每个闭包都有一个单独的类型,即使它们是相同的,您也不能比较交叉类型。
正在寻找at a minimal example:
fn main() {
let b = 2;
let a = if true {
|| println!("{}",b)
} else {
|| println!("{}",b)
};
}
我们收到一个编译器错误,可以帮助解释没有两个闭包,即使相同,也没有相同的类型。
Compiling playground v0.0.1 (/playground)
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:6:9
|
3 | let a = if true {
| _____________-
4 | | || println!("{}",b)
| | -------------------- expected because of this
5 | | } else {
6 | | || println!("{}",b)
| | ^^^^^^^^^^^^^^^^^^^^ expected closure,found a different closure
7 | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected type `[closure@src/main.rs:4:9: 4:29 b:_]`
found closure `[closure@src/main.rs:6:9: 6:29 b:_]`
= note: no two closures,even if identical,have the same type
= help: consider boxing your closure and/or using it as a trait object
error: aborting due to previous error
您可以构建包含环境的结构并比较它们,而不是使用闭包,但是我建议您重新考虑您的问题,看看这是否是解决问题的最佳方法。