有人告诉我 Rust 在区分逻辑上有一种语义——因此可以进行删除/削弱,但不包括复制/收缩。
以下代码成功编译:
fn throw_away<A, B>(x: A, _y: B) -> A {
x
}
由于重复是不允许的,因此以下内容无法编译:
fn dup<A>(x: A) -> (A, A) {
(x, x)
}
同样地,这两个也无法编译:
fn throw_away3<A, B>(x: A, f: fn(A) -> B) -> A {
x;
f(x)
}
fn throw_away4<A, B>(x: A, f: fn(A) -> B) -> A {
throw_away(x, f(x))
}
削弱也是可以观察到的。
fn weaken<A, B, C>(f: fn(A) -> B) -> impl Fn(A, C) -> B {
move |x: A, y: C| f(x)
}
我们返回的是 impl Fn(A, C) -> B
而非 fn(A, C) -> B
。是否有办法返回 fn(A, C) -> B
呢?如果不行也没关系,我只是好奇。
另外,我希望能够将 A
提升为 () -> A
。但是,在Rust中函数可以被复制并使用多次。例如:
fn app_twice(f: fn(A) -> A, x: A) -> A {
f(f(x))
}
假设有一个名为
lift(x: A) -> fn() -> A
的函数,那么我们可以破坏移动语义。例如,这将允许:fn dup_allowed(x: A) -> (A, A) {
let h = lift(x);
(h(), h())
}
因此,要将
A
提升为 fn() -> A
,我们需要知道该函数是“线性/仿射”的,或只能使用一次。Rust 为此提供了一个类型:FnOnce() -> A
。在下面的示例中,第一个可以编译,而第二个则不行。fn app_once(f: impl FnOnce(A) -> A, x: A) -> A {
f(x)
}
fn app_twice2(f: impl FnOnce(A) -> A, x: A) -> A {
f(f(x))
}
以下函数互为反函数(可能是这样,我不太清楚Rust的语义是否真正互为反函数):
fn lift_up<A>(x: A) -> impl FnOnce() -> A {
move || x
}
fn lift_up_r<A>(f: impl FnOnce() -> A) -> A {
f()
}
由于fn dup<A>(x: A) -> (A, A) { (x,x) }
无法编译,我认为以下可能是一个问题:
fn dup<A>(x: fn() -> A) -> (A, A) {
(x(), x())
}
看起来 Rust 对于类型
fn(A) -> B
做了一些特殊处理。为什么在上述例子中我不需要声明 x 是可重用/可复制的?
也许有些不同。声明函数是一件特殊的事情,
fn f(x: A) -> B { ... }
是表明 A -> B
的一个特定证明。因此,如果需要多次使用 f
,它可以被重新证明多次,但是 fn(A) -> B
是完全不同的东西:它不是一个构造出来的东西,而是一个假设性的东西,并且必须使用 fn(A) -> B
来说明它们是可复制的。实际上,我一直认为它更像是一个自由可复制的实体。这是我的简单类比:
fn my_fun<A,B>(x :A) -> B { M }
表示 x:A |- M:Bfn(A) -> B
表示 !(A -o B),因此可以自由复制- 因此,
fn () -> A
表示 !(() -o A) = !A ,因此fn () -> A
是对 A 进行 (co)free 复制 fn dup_arg<A: Copy>(x: A) -> B { M }
表示 A 具有复制或是一个余单子impl FnOnce (A) -> B
表示 A -o B
impl Fn(A) -> B
是什么?通过一些尝试,似乎 fn(A) -> B
比 Fn(A) -> B
更严格。我错过了什么?
fn
,因为它们是“Copy”,这意味着它们仅持有可轻松克隆的信息,就像数字一样。fn
只是可执行文件中函数的地址,复制它只涉及到复制指针。但对于闭包来说情况并非如此,闭包可能会捕获任意状态,就像您的“lift”示例一样。 - user4815162342fn(...)
总是简单引用全局数据。实现Fn(...)
trait 的类型不需要这样。如果将fn()
传递给通用代码(可以与任何Fn
一起使用,而不仅仅是一个具体的fn
),那么在通用代码内部无法复制它们,除非您明确指定+ Copy
(在这种情况下,lift
返回的函数将不符合条件)。impl Fn(...)
是一个匿名类型,只被知道实现了Fn(...)
trait。你的问题实际上是一个非常有趣的阅读,但我不确定实际问题是什么。 - user4815162342