You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中如何实现将Result解包作为常量枚举变体或结构体常量?

如何在Rust中实现通过常量方式获取Result解包后的Address值?

问题背景

已了解如何为枚举定义常量关联值,但希望更进一步:让枚举变体或结构体关联常量直接返回Result解包后的Ok值,核心需求是通过TokenAddress::HERO直接获取Address类型的值。

尝试的初始代码因expect不是const fn无法编译,且不想用lazy_static!逐个定义变量的繁琐方式:

use std::str::FromStr;

#[derive(Debug, PartialEq, Hash)]
struct Address(String);

#[derive(Debug, PartialEq)]
enum Error {
    ParsePointError
}

impl FromStr for Address { // conversion from `&str` to `Address` returns a `Result`
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() >= 20usize {
            return Err(Error::ParsePointError)
        }
        Ok(Address(s.to_string()))
    }
}

struct TokenAddress {}

impl TokenAddress {
    pub const HERO: Address = Address::from_str("0x1234567").expect("ERROR: Unable to parse `HERO`");
}

fn main() {
    let hero_token_address = TokenAddress::HERO;
    println!("{:?}", hero_token_address);
}

解决方案

方案1:将验证逻辑转为const fn,编译期解包Result

把Address的验证逻辑移到自定义的const fn中,再通过编译期的match断言解包Result,避免使用非const的expect:

use std::str::FromStr;

#[derive(Debug, PartialEq, Hash)]
struct Address(String);

#[derive(Debug, PartialEq)]
enum Error {
    ParsePointError
}

impl Address {
    // 转为const构造函数,包含地址验证逻辑
    pub const fn new(s: &str) -> Result<Self, Error> {
        if s.len() >= 20 {
            Err(Error::ParsePointError)
        } else {
            Ok(Address(s.to_string()))
        }
    }
}

impl FromStr for Address {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::new(s)
    }
}

struct TokenAddress {}

impl TokenAddress {
    // 编译期match断言,无效地址直接触发编译错误
    pub const HERO: Address = match Address::new("0x1234567") {
        Ok(addr) => addr,
        Err(_) => panic!("Invalid address for HERO"),
    };
}

fn main() {
    let hero_token_address = TokenAddress::HERO;
    println!("{:?}", hero_token_address);
}

方案2:使用宏批量生成常量(解决多地址定义繁琐问题)

如果需要定义大量Token地址,用宏批量生成常量,避免重复代码:

use std::str::FromStr;

#[derive(Debug, PartialEq, Hash)]
struct Address(String);

#[derive(Debug, PartialEq)]
enum Error {
    ParsePointError
}

impl Address {
    pub const fn new(s: &str) -> Result<Self, Error> {
        if s.len() >= 20 {
            Err(Error::ParsePointError)
        } else {
            Ok(Address(s.to_string()))
        }
    }
}

struct TokenAddress {}

// 批量生成Token地址常量的宏
macro_rules! token_addresses {
    ($($name:ident = $value:expr),* $(,)?) => {
        impl TokenAddress {
            $(
                pub const $name: Address = match Address::new($value) {
                    Ok(addr) => addr,
                    Err(_) => panic!("Invalid address for {}", stringify!($name)),
                };
            )*
        }
    };
}

// 一行定义多个Token地址
token_addresses! {
    HERO = "0x1234567",
    ELIXIR = "0xabcdef",
    GOLD = "0x890123",
}

fn main() {
    let hero_token_address = TokenAddress::HERO;
    let elixir_token_address = TokenAddress::ELIXIR;
    println!("{:?}", hero_token_address);
    println!("{:?}", elixir_token_address);
}

方案3:用枚举变体关联预验证地址(可选)

如果更倾向用枚举组织Token类型,可以为每个变体关联预验证的Address:

use std::str::FromStr;

#[derive(Debug, PartialEq, Hash)]
struct Address(String);

#[derive(Debug, PartialEq)]
enum Error {
    ParsePointError
}

impl Address {
    pub const fn new(s: &str) -> Result<Self, Error> {
        if s.len() >= 20 {
            Err(Error::ParsePointError)
        } else {
            Ok(Address(s.to_string()))
        }
    }
}

#[derive(Debug, PartialEq)]
enum TokenType {
    Hero,
    Elixir,
}

impl TokenType {
    pub const fn address(&self) -> Address {
        match self {
            TokenType::Hero => match Address::new("0x1234567") {
                Ok(addr) => addr,
                Err(_) => panic!("Invalid address for Hero"),
            },
            TokenType::Elixir => match Address::new("0xabcdef") {
                Ok(addr) => addr,
                Err(_) => panic!("Invalid address for Elixir"),
            },
        }
    }
}

fn main() {
    let hero_address = TokenType::Hero.address();
    println!("{:?}", hero_address);
}

关键说明

  • 编译期验证:所有方案都在编译阶段完成地址有效性检查,无效地址会直接触发编译错误,避免运行时panic。
  • 版本要求:确保使用Rust 1.59+,因为String::to_string()在该版本后支持const fn调用;如果使用更低版本,可以将Address的字段改为&'static str适配。

内容的提问来源于stack exchange,提问作者Jim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:17:30