- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我无法实现这个 LISP 构造
(defun foo (n)
(lambda (i) (incf n i)))
使用rust 。我试过this :
use std::ops::Add;
fn f<T: Add>(n: T) -> Box<Fn(T) -> T> {
Box::new(move |i: T| n + i)
}
fn main() {
let adder = f(2);
assert_eq!(4, adder(2));
}
但它会导致错误:
error: mismatched types:
expected `T`,
found `<T as core::ops::Add>::Output`
(expected type parameter,
found associated type) [E0308]
Box::new(move |i: T| n + i)
^~~~~
似乎为外部函数定义的特征 Add
没有转移到内部闭包中。
是否可以实现这样的构造?
可以用具体类型而不是泛型来实现这个函数:
fn f(n: i32) -> Box<Fn(i32) -> i32> {
Box::new(move |i| n + i)
}
最佳答案
通用版本有几个问题。
首先,您提供的错误发生是因为 T: Add
不足以指定输出类型:您需要对关联类型施加约束 <T as Add>::Output
以及(参见 Add
文档):
fn f<T: Add<Output=T>>(n: T) -> Box<Fn(T) -> T> {
Box::new(move |i: T| n + i)
}
或者,您可以让闭包返回 <T as Add>
的输出类型:
fn f<T: Add>(n: T) -> Box<Fn(T) -> T::Output> {
Box::new(move |i: T| n + i)
}
但是,现在您会收到以下错误:
<anon>:4:10: 4:37 error: the parameter type `T` may not live long enough [E0310]
<anon>:4 Box::new(move |i: T| n + i)
^~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:4:10: 4:37 help: see the detailed explanation for E0310
<anon>:4:10: 4:37 help: consider adding an explicit lifetime bound `T: 'static`...
<anon>:4:10: 4:37 note: ...so that the type `[closure@<anon>:4:19: 4:36 n:T]` will meet its required lifetime bounds
<anon>:4 Box::new(move |i: T| n + i)
^~~~~~~~~~~~~~~~~~~~~~~~~~~
这里的问题是 T
可能在其中包含引用(之后,它是一个通用类型 - 它可以包含任何内容);然而,Box<Fn(T) -> T>
隐式意味着此特征对象内的任何内容都必须是 'static
,即编译器自动添加 'static
约束:Box<Fn(T) -> T + 'static>
.但是,您的闭包会捕获 T
其中可以包含任何引用,而不仅仅是 'static
.
修复它的最通用方法是添加显式生命周期约束 T
和 Box<Fn(T) -> T>
:
fn f<'a, T: Add<Output=T> + 'a>(n: T) -> Box<Fn(T) -> T + 'a> {
Box::new(move |i: T| n + i)
}
或者,您可以指定 T
是'static
,尽管这不必要地限制了代码的通用性:
fn f<T: Add<Output=T> + 'static>(n: T) -> Box<Fn(T) -> T> {
Box::new(move |i: T| n + i)
}
然而,这仍然无法编译:
<anon>:4:31: 4:32 error: cannot move out of captured outer variable in an `Fn` closure
<anon>:4 Box::new(move |i: T| n + i)
^
发生此错误是因为 Rust 中的加法(即 Add
特征)按值工作 - 它消耗两个参数。对于 Copy
类型,比如数字,没关系——它们总是被复制。但是,编译器不能假定泛型类型参数也指定 Copy
类型,因为没有相应的界限,因此它假定类型为 T
的值只能四处移动。但是,您指定返回的闭包是 Fn
,因此它通过引用获取其环境。您不能移出引用,这就是此错误的原因。
有多种方法可以修复此错误,最简单的方法是添加 Copy
绑定(bind):
fn f<'a, T: Add<Output=T> + Copy + 'a>(n: T) -> Box<Fn(T) -> T + 'a> {
Box::new(move |i: T| n + i)
}
现在它可以编译了。
一种可能的替代方法是返回 FnOnce
按值获取环境的闭包:
fn f<'a, T: Add<Output=T> + 'a>(n: T) -> Box<FnOnce(T) -> T + 'a> {
Box::new(move |i: T| n + i)
}
但是,它有两个问题。首先,顾名思义,FnOnce
只能调用一次,因为在第一次调用时它的环境被消耗掉了,下次就没有什么可以调用的了。这可能过于局限。其次,不幸的是,Rust 不能调用 Box<FnOnce()>
完全关闭。这是一个实现问题,应该在未来解决;现在有一个不稳定的 FnBox
trait 来解决这个问题。
甚至另一种选择是使用引用而不是值:
fn f<'a, T: 'a>(n: T) -> Box<Fn(T) -> T + 'a> where for<'b> &'b T: Add<T, Output=T> {
Box::new(move |i: T| &n + i)
}
现在我们指定它而不是 T
, &'b T
终生'b
必须与 T
相加.这里我们使用 Add
的事实trait 也被重载以引用原始类型。这可能是该函数最通用的版本。
关于rust - 如何在用作函数结果的闭包内应用特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34063272/
我正在尝试对 StockData 表执行 OHCL sql 查询 (SQL Server 2012)。每天有数千行添加到表中,我想获取每天的开盘价、最高价、最低价和收盘价数据。 建表sql如下:
我是一名优秀的程序员,十分优秀!