gpt4 book ai didi

rust - 为什么对实现 Fn 特征的特征的引用不可调用?

转载 作者:行者123 更新时间:2023-11-29 08:18:47 25 4
gpt4 key购买 nike

我找到了自己对 my own question 的答案如下

trait Mu<T> {
fn unroll(&self, &Mu<T>) -> T;
}

impl<T, F:Fn(&Mu<T>) -> T> Mu<T> for F {
fn unroll(&self, o:&Mu<T>) -> T { self(o) }
}

fn y<T, F:Fn(T) -> T>(f:&F) -> T {
(&|w:&Mu<T>| { w.unroll(w) }).unroll(&|w:&Mu<T>| { f(w.unroll(w)) })
}

它编译并完全回答了问题。但为了让它更漂亮,我实现了 Fn Mu<T> 的特征如下所示:

impl<'a, T> Fn<&'a Mu<T>> for &'a Mu<T> {
extern "rust-call" fn call(&self, o: &'a Mu<T>) -> T {
self.unroll(o)
}
}

impl<'a, T> FnMut<&'a Mu<T>> for &'a Mu<T> {
extern "rust-call" fn call_mut(&mut self, o: &'a Mu<T>) -> T {
self.unroll(o)
}
}

impl<'a, T> FnOnce<&'a Mu<T>> for &'a Mu<T> {
type Output = T;
extern "rust-call" fn call_once(self, o: &'a Mu<T>) -> T {
self.unroll(o)
}
}

有特点

#![feature(fn_traits)]
#![feature(unboxed_closures)]

我想把 y 组合子写成

fn y1<T, F:Fn(T) -> T>(f:&F) -> T {
(&|w:&Mu<T>| { w(w) })(&|w:&Mu<T>| { f(w(w)) })
}

但这不编译。错误信息:

rustc 1.19.0-nightly (78d8416ca 2017-06-17)
error[E0618]: expected function, found `&Mu<T>`
--> <anon>:36:20
|
36 | (&|w:&Mu<T>| { w(w) })(&|w:&Mu<T>| { f(w(w)) })
| ^^^^
|
note: defined here
--> <anon>:36:8
|
36 | (&|w:&Mu<T>| { w(w) })(&|w:&Mu<T>| { f(w(w)) })
| ^

error[E0618]: expected function, found `&Mu<T>`
--> <anon>:36:44
|
36 | (&|w:&Mu<T>| { w(w) })(&|w:&Mu<T>| { f(w(w)) })
| ^^^^
|
note: defined here
--> <anon>:36:30
|
36 | (&|w:&Mu<T>| { w(w) })(&|w:&Mu<T>| { f(w(w)) })
| ^

为什么 Rust 不能找出给定的 Fn执行?有没有办法改善这一点?

进一步的尝试表明它与那些特性无关,甚至与闭包无关。即使是答案中显示的示例 Shepmaster 也不是最小的。一个最小的示例如下所示:

trait T1 {}

trait T2 {}

impl<'a> T1 for &'a T2 {}

struct S {}

impl T2 for S {}

fn main() {
let t2: &T2 = &S {};
let t1: &T1 = &t2; //This is OK
let t3: &T1 = t2; //E0308: Expecting `T1`, found `T2`
}

问题是我们试图为特征对象引用实现特征,然后我们需要在将特征对象转换为目标特征的特征对象时添加额外的引用。

最佳答案

在与 Rust 开发人员讨论后,我们认为这是某种错误。为此,我们提交了 issue 42736 .

一个较小的例子表明问题与特征是分开的。它实际上是任何引用,而不仅仅是特征:

#![feature(fn_traits)]
#![feature(unboxed_closures)]

struct S;

fn repro_ref(thing: &S) {
thing();
}

impl<'a> FnOnce<()> for &'a S {
type Output = ();

extern "rust-call" fn call_once(self, _arg: ()) -> () {}
}

fn main() {}

对此有一个解决方法,即采用另一个引用:

fn ok_ref_ref(thing: &S) {
(&thing)();
}

虽然这并不能解决原来的例子:

fn y1<T, F>(f: &F) -> T
where
F: Fn(T) -> T,
{
(&|w: &Mu<T>| (&w)(w))(&|w: &Mu<T>| f((&w)(w)))
}
error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
--> src/main.rs:41:19
|
41 | (&|w: &Mu<T>| (&w)(w))(&|w: &Mu<T>| f((&w)(w)))
| ^^^^^^^

那是因为 Fn* 的原始实现特质不太正确。参数应该是单个元组。请注意 Fn<(&'a Mu<T>,)> 中的括号和尾随逗号.

总而言之,这有效:

#![feature(fn_traits)]
#![feature(unboxed_closures)]

trait Mu<T> {
fn unroll(&self, &Mu<T>) -> T;
}

impl<T, F> Mu<T> for F
where
F: Fn(&Mu<T>) -> T,
{
fn unroll(&self, o: &Mu<T>) -> T {
self(o)
}
}

impl<'a, T> Fn<(&'a Mu<T>,)> for &'a Mu<T> {
extern "rust-call" fn call(&self, o: (&'a Mu<T>,)) -> T {
self.unroll(o.0)
}
}

impl<'a, T> FnMut<(&'a Mu<T>,)> for &'a Mu<T> {
extern "rust-call" fn call_mut(&mut self, o: (&'a Mu<T>,)) -> T {
self.call(o)
}
}

impl<'a, T> FnOnce<(&'a Mu<T>,)> for &'a Mu<T> {
type Output = T;
extern "rust-call" fn call_once(mut self, o: (&'a Mu<T>,)) -> T {
self.call_mut(o)
}
}

fn y1<T, F>(f: &F) -> T
where
F: Fn(T) -> T,
{
(&|w: &Mu<T>| (&w)(w))(&|w: &Mu<T>| f((&w)(w)))
}

fn main() {}

我还委托(delegate)了来自 Fn* 的电话特征彼此避免重复实现。

关于rust - 为什么对实现 Fn 特征的特征的引用不可调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44614206/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com