我们如何在Rust中创建一个大小函数trait?

k2fxgqgv  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(115)

在下面的代码中,据我理解,SimpleSpawner应该有一个已知的大小,因为它相当于一个函数指针+一个单个u8值,但是这段代码给出了错误the size for values of type(dyn SimpleSpawner<for 'a> Output = u8> + 'static)cannot be known at compilation time。理想情况下,我可以使用函数指针,但函数指针和闭包在Rust中不兼容。
Rust Playground Link

#[derive(Clone)]
pub struct RandomTable<T> {
    pub entries: Vec<T>,
}

impl<T> RandomTable<T> {
    pub fn new() -> Self {
        RandomTable {
            entries: Vec::new(),
        }
    }
}

// pub type SimpleSpawner = fn(u8) -> u8;
// pub type SimpleSpawner = dyn Fn(&mut u8) -> u8;
pub trait SimpleSpawner: Fn(&mut u8) -> u8 + Sized {}

// changed from `-> RandomTable<SimpleSpawner>`
pub fn room_table(map_depth: i32) -> RandomTable<dyn SimpleSpawner> {
  RandomTable::new()
}
fd3cxomn

fd3cxomn1#

这里有不少误解。
SimpleSpawner应该有一个已知的大小,因为它相当于一个函数指针+一个u8值
SimpleSpawnertrait。这意味着它的大小是未知的,它可能是一个实现它的千兆字节大的结构。trait仅仅意味着一个给定的类型具有特定的功能,它对它的大小没有任何说明。
Sized trait仍然没有说明实际大小。它只是说,在编译时,编译器现在知道它的大小。有许多类型没有大小,这意味着编译器不能争论它们的大小,因此它们必须通过引用(&对unsized traits的引用具有已知的大小)或通过Box(这意味着我们将它们移到堆上,因此在堆栈上我们不再关心它们的大小)进行交互。
函数指针+单个u8值
我不知道你从哪里得到的“单个u8值”-即使它是这样的,它也只是一个函数指针。u8是一个参数,在运行时传递给它,它不会是对象的一部分。
函数指针和闭包在Rust中不兼容
这是部分正确的,但Fn不是函数指针。这里所指的是捕获闭包与fn函数指针不兼容。事实上,每个闭包都实现了Fn变体之一。
这里简单回顾一下:

  • fn-简单的函数指针。它对外部的引用为零,并且是完全独立的。
  • Fn-可以通过引用调用的函数类型。可以不变地捕获外部变量。
  • FnMut-可以通过可变引用调用的函数类型。可以不变地捕获外部变量。
  • FnOnce-一种只能由所有权调用的函数类型,它在调用时被消耗,因此只能调用一次。可以执行只能执行一次的操作(如可变消耗)。

下面是一个非常全面的所有可能组合的例子:

struct MyStruct;

impl MyStruct {
    fn immutable_action(&self) {
        println!("\t\tImmutable action!");
    }
    fn mutable_action(&mut self) {
        println!("\t\tMutable action!");
    }
    fn consuming_action(self) {
        println!("\t\tConsuming action!");
    }
}

fn run_functionpointer(f: fn()) {
    println!("run_functionpointer");
    // Can be called multiple times. Not compatible with capturing closures.
    f();
    f();
}

fn run_immutable(f: &impl Fn()) {
    println!("run_immutable");
    // Can be called multiple times and doesn't require `mut`.
    f();
    f();
}
fn run_mutable(f: &mut impl FnMut()) {
    println!("run_mutable");
    // Can be called multiple times, but requires `&mut`.
    f();
    f();
}
fn run_consuming(f: impl FnOnce()) {
    println!("run_consuming");
    // Cannot be called multiple times.
    f();
    // this would be a compiler error:
    // f();
}

fn main() {
    // Simple closure that doesn't reference any outside variables.
    // Compatible with `fn`, `Fn`, `FnMut` and `FnOnce`.
    let mut simple_closure = || {
        println!("\tSimple closure!");
    };
    run_functionpointer(simple_closure);
    run_immutable(&simple_closure);
    run_mutable(&mut simple_closure);
    run_consuming(simple_closure);

    // Closure that captures one outside object via reference.
    // Compatible with `Fn`, `FnMut` and `FnOnce`.
    // **not** compatible with `fn` because `fn` is just a simple pointer
    // and has no space to store the captured data.
    let captured_variable = MyStruct;
    let mut capturing_closure = || {
        println!("\tCapturing closure!");
        let val = &captured_variable;
        val.immutable_action();
        // Those would be compiler errors because they require mutability or ownership:
        // val.mutable_action();
        //val.consuming_action();
    };

    //run_functionpointer(capturing_closure); // ERROR: "closures can only be coerced to `fn` types if they do not capture any variables"
    run_immutable(&capturing_closure);
    run_mutable(&mut capturing_closure);
    run_consuming(capturing_closure);

    // Closure that captures one outside object via `mut` reference.
    // Compatible with `FnMut` and `FnOnce`.
    // **not** compatible with `Fn` because `Fn` cannot capture `&mut` references.
    let mut mutably_captured_variable = MyStruct;
    let mut mutably_capturing_closure = || {
        println!("\tMutably capturing closure!");
        let val = &mut mutably_captured_variable;
        val.immutable_action();
        val.mutable_action();
        // Would be compiler error because it requires ownership:
        //val.consuming_action();
    };

    //run_functionpointer(mutably_capturing_closure);
    //run_immutable(&mutably_capturing_closure); // ERROR: "closure is `FnMut` because it mutates the variable `mutably_captured_variable`"
    run_mutable(&mut mutably_capturing_closure);
    run_consuming(mutably_capturing_closure);

    // Closure that consumes an outside object.
    // Compatible with `FnOnce` only.
    // **not** compatible with `FnMut` because `FnMut` can be called multiple times.
    // But consuming the outside variable can only be done once.
    let owned_variable = MyStruct;
    let mut owning_closure = || {
        println!("\tOwning closure!");
        let mut val = owned_variable;
        // Everything is allowed, as we own the variable.
        // Note that `consuming_action` destroys `val`, however,
        // so this function can only be called once.
        val.immutable_action();
        val.mutable_action();
        val.consuming_action();
    };

    //run_functionpointer(owning_closure);
    //run_immutable(&owning_closure);
    //run_mutable(&mut owning_closure); // ERROR: "closure is `FnOnce` because it moves the variable `owned_captured_variable` out of its environment"
    run_consuming(owning_closure);
}
run_functionpointer
        Simple closure!
        Simple closure!
run_immutable
        Simple closure!
        Simple closure!
run_mutable
        Simple closure!
        Simple closure!
run_consuming
        Simple closure!
run_immutable
        Capturing closure!
                Immutable action!
        Capturing closure!
                Immutable action!
run_mutable
        Capturing closure!
                Immutable action!
        Capturing closure!
                Immutable action!
run_consuming
        Capturing closure!
                Immutable action!
run_mutable
        Mutably capturing closure!
                Immutable action!
                Mutable action!
        Mutably capturing closure!
                Immutable action!
                Mutable action!
run_consuming
        Mutably capturing closure!
                Immutable action!
                Mutable action!
run_consuming
        Owning closure!
                Immutable action!
                Mutable action!
                Consuming action!

相关问题