Generics 由另一个参数限定的泛型参数

Generics 由另一个参数限定的泛型参数,generics,rust,traits,Generics,Rust,Traits,我正在写一个模拟框架。为此,我需要接受一个函数,该函数可以用作另一个函数的替换,并将其存储。我当前的设计通过强制相同的输入和输出类型来实现这一点,但在强制正确的生命周期时完全失败 相反,我需要编写一个通用函数,它接受一个基函数及其替换: fn main() { selector(foo, baz, "local", false); selector(bar, baz, "local", false); selector(foo, bar, "local", false);

我正在写一个模拟框架。为此,我需要接受一个函数,该函数可以用作另一个函数的替换,并将其存储。我当前的设计通过强制相同的输入和输出类型来实现这一点,但在强制正确的生命周期时完全失败

相反,我需要编写一个通用函数,它接受一个基函数及其替换:

fn main() {
    selector(foo, baz, "local", false);
    selector(bar, baz, "local", false);
    selector(foo, bar, "local", false); // SHOULD FAIL, bar is NOT substitute of foo
}

fn foo(_: &str) -> &'static str {
    "foo"
}
fn bar(s: &str) -> &str {
    s
}
fn baz(_: &str) -> &'static str {
    "baz"
}

// DOES NOT COMPILE
// fn selector<U, V, F: Fn(U) -> V, G: F>(base: F, subs: G, arg: U, use_base: bool) -> V {
//     match use_base {
//         true => base(arg),
//         false => subs(arg),
//     }
// }

// COMPILES, but is too weak
fn selector<U, V, F: Fn(U) -> V, G: Fn(U) -> V>(base: F, subs: G, arg: U, use_base: bool) -> V {
    match use_base {
        true => base(arg),
        false => subs(arg),
    }
}
baz
foo
bar
的替代品,因为它返回的字符串既可以用来代替
静态的
字符串,也可以依赖于借用
bar
不是
foo
的替代品,因为借用的值不能代替
的静态值

我想创建这样的东西,但它无法编译:

//                            FAILURE
//                               V
fn selector<U, V, F: Fn(U) -> V, G: F>(base: F, subs: G) {...}
//失败
//五
fn选择器V,G:F>(基:F,子:G){…}

问题是我无法表达
F
G
之间的关系。Rust似乎没有混凝土类型的超类型概念。

Rust也知道类型的这些“兼容性”:都是关于。诀窍是使两个参数具有相同的类型,至少就函数而言是如此

让我们先试试更简单的方法:

// Both arguments have the same type (including the same lifetime)
fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { 
    x 
}

let outer = 3;
{
    let inner = 27;
    println!("{}", foo(&outer, &inner));
}
如果我们这样尝试,不幸的是仍然会得到一个错误:“预期的fn项,发现了不同的fn项”。这与“函数项与函数指针”问题有关。你可以了解更多关于这方面的信息。遗憾的是,在这种情况下,对函数指针的强制并没有起作用,因此一种方法是显式地强制转换函数:

type FnStatic = fn(&str) -> &'static str;
type FnWeaker = fn(&str) -> &str;

selector(foo as FnStatic, baz as FnStatic, "local", false);
selector(bar as FnWeaker, baz as FnStatic, "local", false);
selector(foo as FnStatic, bar as FnWeaker, "local", false); 
()

这实际上和预期的一样:前两个调用很好,但第三个错误是:

错误[E0308]:类型不匹配
-->src/main.rs:7:31
|
7 |选择器(foo为FnStatic,条形图为FnStatic,“本地”,错误);
|^^^^^^^^^^^^^^^^^^^^^^^^^^预期的混凝土寿命,找到绑定的寿命参数
|
=注意:预期类型为`for&str`
为&'r str找到类型``
然而,在调用站点显式转换函数类型仍然有点难看。不幸的是,我还没有找到一个方法来隐藏这一点。我尝试编写一个强制强制执行强制的宏,但当函数指针具有不同类型(包括第二个示例)时,该宏不起作用

fn selector<U, V, F: Fn(U) -> V>(base: F, subs: F, arg: U, use_base: bool) -> V {
    match use_base {
        true => base(arg),
        false => subs(arg),
    }
}
type FnStatic = fn(&str) -> &'static str;
type FnWeaker = fn(&str) -> &str;

selector(foo as FnStatic, baz as FnStatic, "local", false);
selector(bar as FnWeaker, baz as FnStatic, "local", false);
selector(foo as FnStatic, bar as FnWeaker, "local", false);