我在借阅判断器上遇到了问题;以下是我正在try 的简化版本:

trait CommitmentScheme<In> {
    type Com;

    fn commit(input: In) -> Self::Com;
    
    fn open(com1: &Self::Com, com2: &Self::Com);
}

fn prove<CS: for<'a> CommitmentScheme<&'a [u32]>>() {
    let msg1 = vec![1u32];
    let com1 = CS::commit(&msg1);
    let msg2 = vec![2u32];
    let com2 = CS::commit(&msg2);
    CS::open(&com1, &com2);
}

Playground link

这无法编译,并出现以下错误,

error[E0597]: `msg2` does not live long enough
  --> src/lib.rs:13:27
   |
12 |     let msg2 = vec![2u32];
   |         ---- binding `msg2` declared here
13 |     let com2 = CS::commit(&msg2);
   |                           ^^^^^ borrowed value does not live long enough
14 |     CS::open(&com1, &com2);
15 | }
   | -
   | |
   | `msg2` dropped here while still borrowed
   | borrow might be used here, when `com1` is dropped and runs the destructor for type `<CS as CommitmentScheme<&[u32]>>::Com`
   |
   = note: values in a scope are dropped in the opposite order they are defined

早些时候声明msg2可以避免该错误,但在我的设置中,直到第一个commit调用之后才能构建msg2.

我对这个问题的理解是,返回的Com有可能保留对提交消息的引用.然而,根据相反的顺序规则,似乎每个promise 都应该在它可能引用的消息之前丢弃.我首先try 了手动drop个promise ,但没有成功.

我还试着声明type Com: 'static;,我认为这基本上可以保证commit返回一些免borrow 的东西(除了可能的静态borrow ,这看起来不是问题).我认为这将确保msg1msg2只在commit调用期间被borrow ,而不是在commit调用之后被borrow ,但错误仍然存在.

推荐答案

问题是for<'a>中的每个生命周期'a都强加了different个实现.这就像CS多次实现CommitmentScheme,每个生命周期执行一次.当open()除以Self::Com时,实际上等于<Self as CommitmentScheme<In>>::Com,其中In包含此处使用的实际生命周期 .因此,这两个参数的生命周期 必须相等.

The reason 'static doesn't work to specify the associated type as non-capturing lifetimes is explained in issue #114801, linked in Tell the compiler that a generic return type doesn't borrow any references to arguments?. The solution is to use a different generic parameter for Com, which can't borrow from the lifetime since it is not declared yet when it is declared:

fn prove<Com, CS: for<'a> CommitmentScheme<&'a [u32], Com = Com>>() {
    let msg1 = vec![1u32];
    let com1 = CS::commit(&msg1);
    let msg2 = vec![2u32];
    let com2 = CS::commit(&msg2);
    CS::open(&com1, &com2);
}

Rust相关问答推荐

将内部类型作为参数的泛型 struct 上的方法

无法理解铁 rust &S错误处理

制作一片连续整数的惯用Rust 方法?

在自定义序列化程序中复制serde(With)的行为

可以为rust构建脚本编写单元测试吗?

在IntoIter上调用.by_ref().Take().rev()时会发生什么情况

更合理的方法来设计样条线函数器?

在复制类型中使用std::ptr::WRITE_VILAR进行内部可变性的安全性(即没有UnSafeCell)

`actix-web` 使用提供的 `tokio` 运行时有何用途?

Boxing 如何将数据从堆栈移动到堆?

将 &str 或 String 保存在变量中

如何保存指向持有引用数据的指针?

Rust中的一生语法有什么作用?

Rust中是否可以在不复制的情况下从另一个不可变向量创建不可变向量?

我可以在 Rust 中 serde struct camel_case 和 deserde PascalCase

如何将这些测试放在一个单独的文件中?

特征中定义的类型与一般定义的类型之间的区别

无法理解 Rust 对临时值的不可变和可变引用是如何被删除的

仅在运行测试时生成调试输出

为什么可以从闭包中返回私有 struct