Generics 如何在Rust中实现通用链表映射函数?

Generics 如何在Rust中实现通用链表映射函数?,generics,polymorphism,rust,Generics,Polymorphism,Rust,我的牙齿生锈了,我正试图实现一个通用类型的链表。到目前为止,我的cons和len函数工作正常,但是map有一些问题我无法解决 use std::fmt; #[derive(Debug)] enum List<A> { Empty, Cons(A, Box<List<A>>), } fn cons<A>(x: A, xs: List<A>) -> List<A> { return List::

我的牙齿生锈了,我正试图实现一个通用类型的链表。到目前为止,我的
cons
len
函数工作正常,但是
map
有一些问题我无法解决

use std::fmt;

#[derive(Debug)]
enum List<A> {
    Empty,
    Cons(A, Box<List<A>>),
}

fn cons<A>(x: A, xs: List<A>) -> List<A> {
    return List::Cons(x, Box::new(xs));
}

fn len<A>(xs: List<A>) -> i32 {
    match xs {
        List::Empty => 0,
        List::Cons(_, xs) => 1 + len(*xs),
    }
}

fn map<A, B>(f: &Fn(A) -> B, xs: List<A>) -> List<B> {
    match xs {
        List::Empty => List::Empty,
        List::Cons(x, xs) => cons(f(x), map(f, *xs)),
    }
}

fn main() {
    let xs = cons(1, cons(2, cons(3, List::Empty)));
    println!("{:?}", xs);
    println!("{:?}", len(xs));
    let f = |x: i32| x * x;
    println!("{:?})", map(f, xs));
}
预期产出

Cons(1,Cons(2,Cons(3,空)))
3.
缺点(1,缺点(4,缺点(9,空)))
我特别的问题是与

println!("{:?})", map(f, xs));
如果我将该行注释掉,则输出的前两行是正确的。我不确定我的
map
呼叫有什么问题


更新

aochagavia帮助我理解了函数引用问题和第一个所有权问题(显然是很多问题中的!)-我在使用
len
中使用的相同技术时遇到了问题,并且在
map
中遇到了新的错误

我更新的
map
函数如下所示

fn map<A, B>(f: &Fn(A) -> B, xs: &List<A>) -> List<B> {
    match *xs {
        List::Empty => List::Empty,
        List::Cons(x, ref xs) => cons(f(x), map(f, xs)),
    }
}
新的错误是

error[E0009]:无法在同一模式中通过move和ref绑定
-->src/main.rs:23:20
|
23 |列表::Cons(x,ref-xs)=>Cons(f(x),map(f,xs)),
|^-----通过引用和移动使用
|                    |
|按这里的移动模式

错误消息很大,因为它发生在宏中,但如果添加以下内容:
让y=map(f,xs)您可以得到一个较短(并且稍微更精确)的代码:

错误[E0308]:类型不匹配

-->.

好的,谢谢!我看到了与所有权相关的新问题,但我不确定这是否需要一个完全独立的问题,因为仅此答案不会产生我的预期产出。你觉得你能帮我解决所有权问题吗?很有趣。。。好的,但是我不想让我的
map
函数也借用
xs
吗?例如,如果我想在
xs
上映射两次,那么第一次调用map似乎会移动
xs
——当我不改变函数中的值时,必须使用借用操作符来更加明确,这似乎很奇怪。我的想法是,我的代码在几乎每个参数之前都有
&
,同样地,在每个参数之前都有
&
。。。这看起来对吗?要看情况了。在这种情况下,这似乎是合理的,所以你一定要尝试一下。如果您需要帮助,请随时在此处发表意见。更新了我的问题,以证明我无法接受您在
len
中教我的关于借用的内容,并将其应用于
map
:(yikes,看来我还有很长的路要走,才能开始感觉自然。现在,当函数的默认行为是“消费”时,我的直觉反应是混乱的一个论点。它似乎应该像
mut
那样明确地被调用,但在默认情况下不会被使用。我想知道学习锈菌习语会如何随着时间的推移改变这种观点……无论如何,感谢你如此彻底地处理了我的问题。我真的很感激。我正在用锈菌割牙=>祝你好运:)在开始的时候,围绕所有权/借款进行思考可能需要一些工作,但我保证这会变得更容易!当你有问题时,请毫不犹豫地仔细阅读,如果你需要一些不适合这里的讨论/建议,你可以登录IRC()、reddit()或用户论坛()@MatthieuM.谢谢你的热情欢迎。到目前为止,我发现锈迹非常有趣,但是是的,其中一些东西真的让我感到困惑。到目前为止,我使用的任何语言都没有任何可比性(我所知道的)。
let f = |x: i32| x * x;
let ys = map(&f, &xs);
let zs = map(&f, &xs);
println!("{:?})", ys);
println!("{:?})", zs);
fn len<A>(xs: &List<A>) -> i32 {
    match *xs {
        List::Empty => 0,
        List::Cons(_, ref xs) => 1 + len(xs),
    }
}
fn map<A, B>(f: &Fn(&A) -> B, xs: &List<A>) -> List<B> {
    match *xs {
        List::Empty => List::Empty,
        List::Cons(ref x, ref xs) => cons(f(x), map(f, xs)),
    }
}
let f = |x: &i32| (*x) * (*x);
map(&f, &xs);
fn map<F, A, B> (f: F, xs: List<A>) -> List<B>
    where F: Fn(A) -> B
{