未知的Rust类型(涉及闭包)[重复]

u4dcyp6a  于 2023-04-30  发布在  其他
关注(0)|答案(2)|浏览(107)

此问题已在此处有答案

Is there any way to explicitly write the type of a closure?(2个答案)
7天前关闭
考虑到这段有效的Rust代码

fn f(pt: &[f64 ; 3]) -> f64 {
    pt[0] + pt[1] + pt[2]   
}

fn main(){
    let f1d_array: [_; 3] = std::array::from_fn(|dir| {
        move |pt: [f64; 3]| {
            move |x: f64| -> f64 {
                let mut pt_new = pt;
                pt_new[dir] = x;
    
                f(&pt_new)
            }
        }
    });
    
    let pt = [0., 1., 2.];
    let f1d_0 = f1d_array[0](pt);
    assert_eq!(f1d_0(0.),3.);
    assert_eq!(f1d_0(1.),4.);
    
    let f1d_1 = f1d_array[1](pt);
    assert_eq!(f1d_1(0.),2.);
    assert_eq!(f1d_1(1.),3.);
    
    let f1d_2 = f1d_array[2](pt);
    assert_eq!(f1d_2(0.),1.);
    assert_eq!(f1d_2(1.),2.);
}

变量f1d_array的类型是什么?我需要知道它,以便正确定义一个使用f1d_array类型作为输入参数的函数。
这里是Rust playground的链接:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cabc0d9a5f496e3da0b467b9c46f2535

atmip9wb

atmip9wb1#

你可以只写let the compiler tell you,它是[[closure@main.rs:9:9]; 3],但你不能命名这个类型。
所以要创建一个以闭包为参数的函数,你必须求助于泛型:

fn takes_closures<F, G, const N: usize>(a: [F;N])
where
    F: Fn([f64; 3]) -> G,
    G: Fn(f64) -> f64,
{
    todo!()
}

Playground

pengsaosao

pengsaosao2#

@cafce25的答案是正确的;该类型当前不可命名。由于您可能希望您的函数采用任何“类似”闭包的类型,因此在接受闭包时,泛型是大多数情况下的方法。
然而,如果你确定你只需要函数接受你的闭包类型,而不是其他类型,有一种方法可以在unstable rust中命名它的类型:

#![feature(type_alias_impl_trait)]

type F = impl Fn([f64; 3]) -> G;
type G = impl Fn(f64) -> f64;

fn takes_closures(a: [F;3]) {}

Playground
这使用了type_alias_impl_trait特性,该特性允许您通过指定类型的属性来为类型(即使是没有任何名称的类型,例如闭包)给予另一个名称。
这与泛型非常相似,但方向相反。当在函数中使用泛型时,它本质上是在说“我接受任何具有这些属性的值”。但是,当使用这些类型别名时,函数会说:“存在具有这些属性的类型,我可以接受它且只能接受它**”。
它类似于fn(value: impl Trait)fn() -> impl Trait之间的区别。fn() -> impl Traittype = impl Trait都定义了所谓的存在类型。即存在的类型,但你不想/不能通过它们的实际名称引用它们,只能通过它们的属性引用它们。
然而,这里有一个陷阱。注意到我说“存在一个类型”了吗?使用类型别名时,必须在某个地方使用别名,以便编译器知道实际的基础类型是什么。如果你不这样做,编译器会对你大喊:

error: unconstrained opaque type
  --> src/main.rs:40:10
   |
40 | type H = impl Fn(f64) -> f64;
   |          ^^^^^^^^^^^^^^^^^^^
   |
   = note: `H` must be used in combination with a concrete type within the same module

然而,总而言之,这些通常在返回值时使用,而不是在接受值时使用。由于您不能创建fn() -> impl Fn() -> impl Fn(),因此可以使用以下解决方案,因为您可以定义fn() -> F; type F = impl Fn() -> G; type G = impl Fn();
可能存在接受存在类型的用例,例如不能接受泛型的FFI函数。

相关问题