Generics 从泛型方法中的联合样式枚举获取活动值
我有类似以下代码:Generics 从泛型方法中的联合样式枚举获取活动值,generics,enums,type-conversion,rust,Generics,Enums,Type Conversion,Rust,我有类似以下代码: enum Value { Bool(bool), Int(i32), Float(f32), Str(String), } fn get_value(key: &str) -> Value { // read value from file match key { "b" => Value::Bool(true), "i" => Value::Int(666),
enum Value {
Bool(bool),
Int(i32),
Float(f32),
Str(String),
}
fn get_value(key: &str) -> Value {
// read value from file
match key {
"b" => Value::Bool(true),
"i" => Value::Int(666),
"f" => Value::Float(42.),
"s" => Value::Str("The short answer is that you can't. Check out your function prototype:
fn convert<T>(e: &Value) -> T
枚举值{
布尔(布尔),
Int(i32),
浮动(f32),
Str(字符串),
}
fn获取_值(键:&str)->值{
//从文件中读取值
匹配键{
“b”=>Value::Bool(真),
“i”=>Value::Int(666),
“f”=>Value::Float(42.),
“s”=>Value::Str(“简而言之,您不能。请查看您的函数原型:
fn parse<F>(&self) -> Result<F, F::Err>
where F: FromStr
{
FromStr::from_str(self)
}
是这里真正的英雄,许多类型都实现了它。任何实现FromStr
的类型都可以与parse
一起使用
我相信您可以在您的案例中使用FromStr
,因为您的代码没有任何意义。^\u^您的示例代码:
let id: i32 = row.get(0);
let name: String = row.get(1);
我相信您可以借助str的添加一些样板:
enum Value {
Bool(bool),
Int(i32),
Float(f32),
Str(String),
}
fn get_value(key: &str) -> Value {
// read value from file
match key {
"b" => Value::Bool(true),
"i" => Value::Int(666),
"f" => Value::Float(42.),
"s" => Value::Str("Andrea P's answer was really helpful. I adapted it a little and also made a macro to avoid code duplication in the impl Convert
s. Here's the result just in case anyone is interested:
trait Convert : Sized {
fn convert(Value) -> Option<Self>;
}
macro_rules! impl_convert {
($t:ty, $id:ident) => (
impl Convert for $t {
fn convert(v: Value) -> Option<$t> {
match v {
Value::$id(x) => Some(x),
_ => None,
}
}
}
)
}
impl_convert!(bool, Bool);
impl_convert!(i32, Int);
impl_convert!(f32, Float);
impl_convert!(String, Str);
fn query<T: Convert>(t: &str) -> T {
// … validation etc.
match T::convert(get_value(t)) {
Some(x) => x,
None => panic!("`{}` has an incorrect type", t),
}
}
使用std::collections::HashMap;
使用std::str::FromStr;
结构配置文件{
原始:HashMap,
}
impl配置文件{
fn从磁盘读取磁盘()->Self{
让mut map=HashMap::new();
插入(“name.into(),“Anna.into());
插入(“points.into(),“210.into());
insert(“debug.into(),“true.into());
配置文件{raw:map}
}
fn get(&self,name:&str)->选项
其中T:FromStr
{
self.raw.get(name.)和| u然后(| v | v.parse().ok())
}
}
fn main(){
让conf=ConfigFile::从磁盘()读取磁盘();
让n:String=conf.get(“name”).unwrap();
让p:i32=conf.get(“points”).unwrap();
设d:bool=conf.get(“调试”).unwrap();
println!(“{}有{}个点,{}”,n,p,d);
}
这里有一个可能的解决方案:
枚举值{
布尔(布尔),
Int(i32),
浮动(f32),
Str(字符串),
}
fn获取_值(键:&str)->值{
//从文件中读取值
匹配键{
“b”=>Value::Bool(真),
“i”=>Value::Int(666),
“f”=>Value::Float(42.),
“s”=>Value::Str(“真的很有帮助。我对它进行了一些修改,还制作了一个宏,以避免在impl Convert
s中出现代码重复。以下是结果,以防有人感兴趣:
trait转换:大小{
fn转换(值)->选项;
}
宏规则!impl\u转换{
($t:ty,$id:ident)=>(
impl转换为$t{
fn转换(v:值)->选项{
比赛五{
值::$id(x)=>Some(x),
_=>没有,
}
}
}
)
}
impl_convert!(bool,bool);
impl_convert!(i32,Int);
impl_convert!(f32,浮点);
impl_convert!(字符串,Str);
fn查询(t:&str)->t{
//…验证等。
匹配T::转换(获取值(T)){
一些(x)=>x,
None=>panic!(“{}`的类型不正确”,t),
}
}
转换
继承大小
以防止:
警告:未为类型Self实现traitcore::marker::Sized
啊,这当然有道理。这基本上创建了一个与strFromStr
并行的特征,但它是根据所讨论的源类型定制的。非常好!尽管为i32
实现特征并为i32
创建关联类型似乎是多余的-我认为您不需要关联类型。
use std::collections::HashMap;
use std::str::FromStr;
struct ConfigFile {
raw: HashMap<String, String>,
}
impl ConfigFile {
fn read_from_disk() -> Self {
let mut map = HashMap::new();
map.insert("name".into(), "Anna".into());
map.insert("points".into(), "210".into());
map.insert("debugging".into(), "true".into());
ConfigFile { raw: map }
}
fn get<T>(&self, name: &str) -> Option<T>
where T: FromStr
{
self.raw.get(name).and_then(|v| v.parse().ok())
}
}
fn main() {
let conf = ConfigFile::read_from_disk();
let n: String = conf.get("name").unwrap();
let p: i32 = conf.get("points").unwrap();
let d: bool = conf.get("debugging").unwrap();
println!("{} has {} points, {}", n, p, d);
}
enum Value {
Bool(bool),
Int(i32),
Float(f32),
Str(String),
}
fn get_value(key: &str) -> Value {
// read value from file
match key {
"b" => Value::Bool(true),
"i" => Value::Int(666),
"f" => Value::Float(42.),
"s" => Value::Str("Andrea P's answer was really helpful. I adapted it a little and also made a macro to avoid code duplication in the impl Convert
s. Here's the result just in case anyone is interested:
trait Convert : Sized {
fn convert(Value) -> Option<Self>;
}
macro_rules! impl_convert {
($t:ty, $id:ident) => (
impl Convert for $t {
fn convert(v: Value) -> Option<$t> {
match v {
Value::$id(x) => Some(x),
_ => None,
}
}
}
)
}
impl_convert!(bool, Bool);
impl_convert!(i32, Int);
impl_convert!(f32, Float);
impl_convert!(String, Str);
fn query<T: Convert>(t: &str) -> T {
// … validation etc.
match T::convert(get_value(t)) {
Some(x) => x,
None => panic!("`{}` has an incorrect type", t),
}
}