首页 > 解决方案 > 如何在结构上实现“方法覆盖”(将闭包传递给结构?)

问题描述

我是 Rust 的新手,仍在学习如何用该语言表示不同的设计模式,而且我最近的背景都是严重的 OO 设计,这无助于思考这个问题。

在下面的示例中,我想将sort_ascending条件消除为更优雅的东西,理想情况下让它在编译时完全解决。

struct MyList {
    ladder: Vec<i32>,
    sort_ascending: bool,
}

impl MyList {
    pub fn new(data: &[i32], sort_ascending: bool) -> MyList {
        return MyList {
            ladder: data.to_vec(),
            sort_ascending: sort_ascending,
        };
    }

    pub fn get_best(&self) -> Option<&i32> {
        if self.sort_ascending {
            return self.ladder.iter().reduce(|a, b| if a >= b { a } else { b });
        } else {
            return self.ladder.iter().reduce(|a, b| if a <= b { a } else { b });
        }
    }
}

fn main() {
    let x = MyList::new(&[10, 4, 30, 2, 5, 2], true);
    let r = x.get_best();
    println!("{:?}", r);

    let x = MyList::new(&[10, 4, 30, 2, 5, 2], false);
    let r = x.get_best();
    println!("{:?}", r);
}

我认为解决方案在于将闭包传递给reduce()可配置的,并尝试了以下几行的许多变体,但均未成功:

struct MyList<F>
    where F : Fn(i32,i32) -> i32
{
    ladder: Vec<i32>,
    sort_closure : F
}

impl<F> MyList<F> 
    where F : Fn(i32,i32) -> i32
{
    pub fn new(data: &[i32], sort_ascending: bool) -> MyList<F> {
        
        if sort_ascending { 
            return MyList {
                ladder: data.to_vec(),
                sort_closure : |a, b| if a >= b { a } else { b },
            };
        } else {
            return MyList {
                ladder: data.to_vec(),
                sort_closure : |a, b| if a <= b { a } else { b },
            };
        }
    }

    pub fn get_best(&self) -> Option<&i32> {
            return self.ladder.iter().reduce(self.sort_closure);
    }
}

fn main() {
    let x = MyList::new(&[10, 4, 30, 2, 5, 2], true);
    let r = x.get_best();
    println!("{:?}", r);

    let x = MyList::new(&[10, 4, 30, 2, 5, 2], false);
    let r = x.get_best();
    println!("{:?}", r);
}

我真的很感激任何关于如何使上述代码编译的指针,或者指向实现这种模式的正确方法的指针。

标签: rust

解决方案


一个直接的解决方法是使用函数指针 ( fn) 而不是尝试在 上使用泛型参数MyList

以下解决方案类似于用户 Jmb 在上述评论中建议的解决方案,但通过进一步简化

  • 避免函数指针中的生命周期
  • 使用std::cmp::{max, min}而不是编写我们自己的闭包(尽管如果您像以前一样自己定义闭包,代码仍然有效)
use std::cmp;

struct MyList {
    ladder: Vec<i32>,
    sort_closure: fn(i32, i32) -> i32,
}

impl MyList {
    pub fn new(data: &[i32], sort_ascending: bool) -> MyList {
        MyList {
            ladder: data.to_vec(),
            sort_closure: match sort_ascending {
                true => cmp::max,
                false => cmp::min,
            },
        }
    }

    pub fn get_best(&self) -> Option<i32> {
        self.ladder.iter().copied().reduce(self.sort_closure)
    }
}

为什么原始方法不起作用

这就是MyList定义的样子:

struct MyList<F>
    where F : Fn(i32,i32) -> i32
{
    ladder: Vec<i32>,
    sort_closure : F
}

这不起作用的原因与 on 的类型参数F有关MyList。在那里拥有类型参数意味着调用者(中的代码main())可以自由地用他们选择MyList<F>的任何F满足Fn(i32,i32) -> i32约束的实例进行实例化。但是,在MyList::new()函数内部,我们定义了自己的两个闭包,然后尝试将其中一个存储在MyList. 这就是矛盾。调用者无法选择要存储的闭包类型,除非间接使用sort_ascending标志。


推荐阅读