Rust 枚举和匹配:它如何区分两个不同的枚举,它们采用两个不同的结构但内容相同
Rust enum and match : How does it distinguishes two different enums that takes in two different struct but same contents
我试图理解以下枚举 from this repo
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub struct InitEscrowArgs {
pub data: EscrowReceive,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub struct ExchangeArgs {
pub data: EscrowReceive,
}
#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub enum EscrowInstruction {
InitEscrow(InitEscrowArgs),
Exchange(ExchangeArgs),
CancelEscrow(),
}
它在这场比赛中使用了它 from this repo。
pub fn process(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let instruction = EscrowInstruction::try_from_slice(instruction_data)?;
match instruction {
EscrowInstruction::InitEscrow(args) => {
msg!("Instruction: Init Escrow");
Self::process_init_escrow(program_id, accounts, args.data.amount)
}
EscrowInstruction::Exchange(args) => {
msg!("Instruction: Exchange Escrow");
Self::process_exchange(program_id, accounts, args.data.amount)
}
EscrowInstruction::CancelEscrow() => {
msg!("Instruction: Cancel Escrow");
Self::process_cancel(program_id, accounts)
}
}
}
我知道这个 try_from_slice 方法获取某种字节数组并将其反序列化。
我不明白它如何确定要使用的枚举值。
枚举有 3 个选择,InitEscrow / Exchange / CancelEscrow,但是什么决定了匹配要知道它应该是哪一个 select?
在我看来,InitEscrowArgs 和 ExchangeArgs 都采用相同的结构。两者都包含 EscrowReceive 数据类型的数据。
方法 try_from_slice
是 BorshDeserialize 特征的一部分,它是在相关枚举上派生的。因此,枚举变体之间的选择是由反序列化器的实现做出的。
为了了解实际情况,我构建了最简单的示例:
use borsh::BorshDeserialize;
#[derive(BorshDeserialize)]
enum Enum {
Variant1(u8),
Variant2,
}
通过使用cargo expand
和一些手动清理,我们可以得到以下等效代码:
impl borsh::de::BorshDeserialize for Enum {
fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
let variant_idx: u8 = borsh::BorshDeserialize::deserialize(buf)?;
let return_value = match variant_idx {
0u8 => Enum::Variant1(borsh::BorshDeserialize::deserialize(buf)?),
1u8 => Enum::Variant2,
_ => {
let msg = format!("Unexpected variant index: {}", variant_idx);
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
msg,
));
}
};
Ok(return_value)
}
}
其中内部 deserialize
调用指的是 impl BorshDeserialize for u8
:
fn deserialize(buf: &mut &[u8]) -> Result<Self> {
if buf.is_empty() {
return Err(Error::new(
ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let res = buf[0];
*buf = &buf[1..];
Ok(res)
}
因此,它的工作方式如下:
- 解串器尝试从输入中提取一个字节;如果有 none - 这是一个错误。
- 这个字节被解释为枚举变体的索引;如果它与其中一个变体不匹配 - 这是一个错误。
- 如果变体包含任何数据,反序列化器会尝试从输入中提取该数据;如果失败(根据内部类型的实现)——这是一个错误。
我试图理解以下枚举 from this repo
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub struct InitEscrowArgs {
pub data: EscrowReceive,
}
#[repr(C)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub struct ExchangeArgs {
pub data: EscrowReceive,
}
#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub enum EscrowInstruction {
InitEscrow(InitEscrowArgs),
Exchange(ExchangeArgs),
CancelEscrow(),
}
它在这场比赛中使用了它 from this repo。
pub fn process(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let instruction = EscrowInstruction::try_from_slice(instruction_data)?;
match instruction {
EscrowInstruction::InitEscrow(args) => {
msg!("Instruction: Init Escrow");
Self::process_init_escrow(program_id, accounts, args.data.amount)
}
EscrowInstruction::Exchange(args) => {
msg!("Instruction: Exchange Escrow");
Self::process_exchange(program_id, accounts, args.data.amount)
}
EscrowInstruction::CancelEscrow() => {
msg!("Instruction: Cancel Escrow");
Self::process_cancel(program_id, accounts)
}
}
}
我知道这个 try_from_slice 方法获取某种字节数组并将其反序列化。
我不明白它如何确定要使用的枚举值。
枚举有 3 个选择,InitEscrow / Exchange / CancelEscrow,但是什么决定了匹配要知道它应该是哪一个 select?
在我看来,InitEscrowArgs 和 ExchangeArgs 都采用相同的结构。两者都包含 EscrowReceive 数据类型的数据。
方法 try_from_slice
是 BorshDeserialize 特征的一部分,它是在相关枚举上派生的。因此,枚举变体之间的选择是由反序列化器的实现做出的。
为了了解实际情况,我构建了最简单的示例:
use borsh::BorshDeserialize;
#[derive(BorshDeserialize)]
enum Enum {
Variant1(u8),
Variant2,
}
通过使用cargo expand
和一些手动清理,我们可以得到以下等效代码:
impl borsh::de::BorshDeserialize for Enum {
fn deserialize(buf: &mut &[u8]) -> Result<Self, std::io::Error> {
let variant_idx: u8 = borsh::BorshDeserialize::deserialize(buf)?;
let return_value = match variant_idx {
0u8 => Enum::Variant1(borsh::BorshDeserialize::deserialize(buf)?),
1u8 => Enum::Variant2,
_ => {
let msg = format!("Unexpected variant index: {}", variant_idx);
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
msg,
));
}
};
Ok(return_value)
}
}
其中内部 deserialize
调用指的是 impl BorshDeserialize for u8
:
fn deserialize(buf: &mut &[u8]) -> Result<Self> {
if buf.is_empty() {
return Err(Error::new(
ErrorKind::InvalidInput,
ERROR_UNEXPECTED_LENGTH_OF_INPUT,
));
}
let res = buf[0];
*buf = &buf[1..];
Ok(res)
}
因此,它的工作方式如下:
- 解串器尝试从输入中提取一个字节;如果有 none - 这是一个错误。
- 这个字节被解释为枚举变体的索引;如果它与其中一个变体不匹配 - 这是一个错误。
- 如果变体包含任何数据,反序列化器会尝试从输入中提取该数据;如果失败(根据内部类型的实现)——这是一个错误。