【问题标题】:Getting unexpected lifetime issue when passing newly constructed array to function将新构造的数组传递给函数时出现意外的生命周期问题
【发布时间】:2021-12-21 13:33:15
【问题描述】:

我一直在开发一个旨在在 Solana 运行时上运行的程序。我最近遇到了一个问题,数组中的第二项被传递到“test2”中会出现某种生命周期错误。当显式生命周期注释添加到 test1 时,此错误消失,但我无法弄清楚它为什么首先出现。

pub fn test1(
    test_account_1: &AccountInfo,
    test_account_2: &AccountInfo,
    mint_account: &AccountInfo,
) -> ProgramResult {
    test2(&[test_account_1.clone(), test_account_2.clone()]);
    return Ok(());
}

pub fn test2(arr: &[AccountInfo]) {
    for a in arr.iter() {
        println!("{}", a.key)
    }
}

错误:

寿命不匹配

...但是来自test_account_1 的数据流入test_account_2 这里是 rustc (E0623)

lib.rs(207, 22):这两种类型声明为 不同的生命周期...

lib.rs(208, 22):

lib.rs(211, 37): ...但是数据 从test_account_1 流入test_account_2 这里

AccountInfo 的定义:

/// Account information
#[derive(Clone)]
pub struct AccountInfo<'a> {
    /// Public key of the account
    pub key: &'a Pubkey,
    /// Was the transaction signed by this account's public key?
    pub is_signer: bool,
    /// Is the account writable?
    pub is_writable: bool,
    /// The lamports in the account.  Modifiable by programs.
    pub lamports: Rc<RefCell<&'a mut u64>>,
    /// The data held in this account.  Modifiable by programs.
    pub data: Rc<RefCell<&'a mut [u8]>>,
    /// Program that owns this account
    pub owner: &'a Pubkey,
    /// This account's data contains a loaded program (and is now read-only)
    pub executable: bool,
    /// The epoch at which this account will next owe rent
    pub rent_epoch: Epoch,
}

【问题讨论】:

  • 请提供重现错误的最小示例(例如在online playground 上)。
  • 除非您有特殊需要,否则我强烈建议您将 &amp;'a Pubkey 字段切换为仅 Pubkey 并拥有数据,并同样摆脱 RefCells 上的生命周期注释。 (理想情况下,我也会摆脱这些 RefCell。它们非常可疑。将 RefCell 公开是非常奇怪的 IMO。很难避免程序崩溃。如果您使用对避免复制,您可能会查看std::borrow::Cow。如果您必须在简单的非通用代码上标记很多生命周期,那么您可能走错了 IMO 路径。
  • AccountInfo 结构取自 Solana 库 (github.com/solana-labs/solana/blob/…),我只是想制作一个可重复性最低的示例。很抱歉造成混乱。

标签: rust solana


【解决方案1】:

为了让您的数组包含对那些AccountsInfo 的引用,它们需要至少存在相同的生命周期。由于它们具有内部边界,因此它们也需要匹配:

pub fn test1<'a>(
    test_account_1: &AccountInfo<'a>,
    test_account_2: &AccountInfo<'a>,
    mint_account: &AccountInfo,
) -> Result<(), ()> {
    test2(&[test_account_1.clone(), test_account_2.clone()]);
    Ok(())
}

Playground

另外,根据您的实际需要,您可能根本不需要克隆:

pub fn test1<'a>(
    test_account_1: &AccountInfo<'a>,
    test_account_2: &AccountInfo<'a>,
    mint_account: &AccountInfo,
) -> Result<(), ()> {
    test2(&[test_account_1, test_account_2]);
    Ok(())
}

pub fn test2(arr: &[&AccountInfo]) {
    for a in arr.iter() {
        println!("{}", a.key)
    }
}

Playground

【讨论】:

  • 我想一个后续问题是为什么如果我将 AccountInfo 更改为像这样为 i32 引用定义了生命周期的结构,我不必声明生命周期?:play.rust-lang.org/…
  • i32 实现Copy。它可以进行简单的按位复制,因此对clone 的调用肯定会创建独立的对象。在这种情况下,生命周期不需要相互匹配,Lifetime Elision 会起作用,因此您无需实际编写它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 2015-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-27
  • 1970-01-01
相关资源
最近更新 更多