Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 根据设置,使用多个闭包中的一个对向量进行排序_Sorting_Rust_Closures - Fatal编程技术网

Sorting 根据设置,使用多个闭包中的一个对向量进行排序

Sorting 根据设置,使用多个闭包中的一个对向量进行排序,sorting,rust,closures,Sorting,Rust,Closures,我想编译以下代码: struct Person { name: String, age: u32, } fn main() { let sort_by = "age"; let x = vec![ Person { name: "Peter".to_string(), age: 18, }, Person { name: "Frank".to

我想编译以下代码:

struct Person {
    name: String,
    age: u32,
}

fn main() {
    let sort_by = "age";

    let x = vec![
        Person {
            name: "Peter".to_string(),
            age: 18,
        },
        Person {
            name: "Frank".to_string(),
            age: 55,
        },
    ];

    let key_func;

    if sort_by == "age" {
        key_func = |item: &Person| {
            return &item.age;
        };
    } else if sort_by == "name" {
        key_func = |item: &Person| {
            return &item.name;
        };
    }

    x.sort_by_key(key_func);
}
我知道为什么这不能编译,但我不知道如何解决它。我尝试了几种不同的方法,包括在Box::new中包装闭包,但我无法让它工作

起初,我想忽略这个问题,只是将所有排序逻辑(包括条件)移动到一个闭包中,但后来我不得不添加一个反向排序选项。因为为了简单起见,我真的想使用*u by_键,所以我尝试使用std::cmp::Reverse,结果是:

use std::cmp::Reverse;

fn main() {
    let reverse = false;

    // ....

    let key_func = |item: &Person| {
        if reverse {
            return Reverse(&item.age);
        } else {
            return &item.age;
        }
    };

    x.sort_by_key(key_func);
}

同样,我理解错误发生的原因,但我不确定如何修复它。

正如您所认识到的,问题是key\u func只能有一个特定的类型,但这两个闭包都有不同的类型

一个是实现FnMut&Person->&u32的类型,另一个是实现FnMut&Person->&String的类型

即使它们都返回相同的类型,即使它们在语法上完全相同,它们也将是两种不同的类型。这就像尝试执行let num:i32=if谓词{0}else{thing}。您可以将它们装箱到具有相同特征的特征对象中,但是装箱FnMut很棘手,因为box没有实现FnMut

还有一个更根本的问题:你

您可以做的一件事是使用更通用的方法,即FnMut&T,&T->排序,并在其中包含逻辑,以了解基于哪些字段返回什么排序,如果您真的想返回,可以使用某种SortBy enum进行指导


另一种选择是在分支本身内简单地调用sort_by_键,以便从中对Vec进行排序,或者如果您想推迟排序,则再次维护某种指示符,例如SortBy enum,您可以在实际需要时使用它具体地执行排序。

您已经知道这个问题,所以我不需要再解释了。这是密码

 let mut cmp_func: Box<Fn(&Person, &Person) -> std::cmp::Ordering> = match sort_by {
    "age" => Box::new(|a, b| a.age.cmp(&b.age)),
    "name" => Box::new(|a, b| a.name.cmp(&b.name)),
    _ => panic!("unknown sort"),
};

if reverse {
    cmp_func = Box::new(move |a, b| cmp_func(a, b).reverse());
}

x.sort_by(|a, b| cmp_func(a, b));

我知道为什么不能编译,为什么会这样?当sort_by既不是name也不是age时会发生什么?您是否尝试过没有任何条件的代码?即使在这种情况下,它也不起作用。如果sort_by既不是name也不是age,就说它是panics。要对集合进行排序,您需要对给定集合元素的类型使用一个比较函数。此比较函数通常采用两个类型相同的参数a和b。您试图实现的是破解单个通用lambda,而不是提供具有相同签名的多个lambda。谢谢!我真的很想使用sort_by_键,因为在我的例子中,确定要排序的数据在很多情况下需要一点仪式性,从辅助存储中获取相关数据,而对于a和`b,代码只需要做两次就更为冗长了。我还模模糊糊地想知道,由于密钥可能会被缓存,所以按密钥排序是否会更快,但我想现在看看代码,情况并非如此。@miracle2k听起来您想要的是不稳定的方法,它可能仍然不适用于您的案例。
x.sort_by(|a, b| {
    let ord = match sort_by {
        "age" => a.age.cmp(&b.age),
        "name" => a.name.cmp(&b.name),
        _ => panic!("unknown sort"),
    };

    if reverse {
        ord.reverse()
    } else {
        ord
    }
});