我有一个简单的分类器:
struct Clf {
x: f64,
}
如果观测值小于x
,则分类器返回0;如果大于,则返回1 x
。
我想为此分类器实现调用运算符。但是,该函数应该能够将float或vector用作参数。对于向量,输出为0或1的向量,其大小与输入向量相同:
let c = Clf { x: 0 };
let v = vec![-1, 0.5, 1];
println!("{}", c(0.5)); // prints 1
println!("{}", c(v)); // prints [0, 1, 1]
Fn
在这种情况下,我该如何编写实现?
impl Fn for Clf {
extern "rust-call" fn call(/*...*/) {
// ...
}
}
简短的答案是:您不能。至少它不会按照您想要的方式工作。我认为最好的证明方法是逐步了解发生的情况,但总体思路是Rust不支持函数重载。
在此示例中,我们将实现FnOnce
,因为Fn
requireFnMut
需要require FnOnce
。因此,如果我们要对所有这些进行排序,则可以针对其他功能特性进行处理。
首先,这是不稳定的,因此我们需要一些功能标志
#![feature(unboxed_closures, fn_traits)]
然后,让我们impl
进行以下操作f64
:
impl FnOnce<(f64,)> for Clf {
type Output = i32;
extern "rust-call" fn call_once(self, args: (f64,)) -> i32 {
if args.0 > self.x {
1
} else {
0
}
}
}
Fn
特质族的参数是通过元组提供的,这就是(f64,)
语法。这是一个只有一个元素的元组。
这一切都很好,现在我们可以做c(0.5)
,尽管c
在我们实现其他特征之前它会消耗很多。
现在让我们对Vec
s做同样的事情:
impl FnOnce<(Vec<f64>,)> for Clf {
type Output = Vec<i32>;
extern "rust-call" fn call_once(self, args: (Vec<f64>,)) -> Vec<i32> {
args.0
.iter()
.map(|&f| if f > self.x { 1 } else { 0 })
.collect()
}
}
在每晚Rust 1.33之前,您不能直接打电话c(v)
,甚至不能打电话c(0.5)
(以前没有用过);我们会收到有关未知函数类型的错误信息。基本上,这些版本的Rust不支持函数重载。但是我们仍然可以使用完全限定的语法调用函数,其中c(0.5)
变为FnOnce::call_once(c, (0.5,))
。
不知道您的概况,我想简单地通过提供以下Clf
两个函数来解决此问题:
impl Clf {
fn classify(&self, val: f64) -> u32 {
if val > self.x {
1
} else {
0
}
}
fn classify_vec(&self, vals: Vec<f64>) -> Vec<u32> {
vals.into_iter().map(|v| self.classify(v)).collect()
}
}
然后,您的用法示例变为
let c = Clf { x: 0 };
let v = vec![-1, 0.5, 1];
println!("{}", c.classify(0.5)); // prints 1
println!("{}", c.classify_vec(v)); // prints [0, 1, 1]
我实际上想制作第二个函数classify_slice
并使它&[f64]
更通用一些,那么您仍然可以Vec
通过引用它们将它与s一起使用c.classify_slice(&v)
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句