实现TryFrom时,我应该使用&str还是String?

6

我有一个类型Instruction,想使用std::convert::TryFrom从字符串转换。

我应该在String上实现还是&str?如果我使用&str,我必须使用&*模式或as_ref()

我有类似这样的东西:Rust Playground永久链接

use std::convert::TryFrom;
enum Instruction {
    Forward, /* other removed for brievity */
}
#[derive(Debug)]
struct InstructionParseError(char);
impl std::convert::TryFrom<&str> for Instruction {
    type Error = InstructionParseError;    
    fn try_from(input: &str) -> Result<Self, Self::Error> {
      match input {
        "F" => Ok(Instruction::Forward),
        _ => unimplemented!(), // For brievity
      }
    }
}

fn main() {
    // I use a string because this input can come from stdio.
    let instr = String::from("F");
    let instr = Instruction::try_from(&*instr);
}

我阅读了这篇回答:Should Rust implementations of From/TryFrom target references or values?,但我想知道最佳选择是什么:实现两者?使用impl高级类型?


我认为你应该只为&str实现它,但是你可以为&String添加一个impl,但这并不是非常重要的。你的类型可以从&str构造,除了String之外的任何结构体都可以有一个字符串表示形式,并且你不能为每种类型都实现TryFrom,让用户将转换为字符串应该没问题。 - Stargateur
是的,但如果用户传递了“val:String”,我将强制用户使用“&*val”或“val.as_ref()”。遗憾的是,编译器消息非常糟糕...如果有惯用的方法,这种情况下就可以避免不良开发者体验,那就太完美了。 - Darnuria
2个回答

2
我认为在阅读 @SirDarius 的评论后,一个解决方案是也为 String 实现,然后在内部使用 as_ref()&*
use std::convert::TryFrom;
enum Instruction {
    Forward, /* other removed for brievity */
}
#[derive(Debug)]
struct InstructionParseError(char);
impl std::convert::TryFrom<String> for Instruction {
    type Error = InstructionParseError;    
    fn try_from(input: String) -> Result<Self, Self::Error> {
        Instruction::try_from(input.as_ref())
    }
}

像这里描述的 Rust 的 From/TryFrom 实现应该针对引用还是值?,也许在将来,如果有一些关于 blanket implementation 的变化,AsRef 将可用。


@SirDarius:哦,感谢您的更正!我假设用法类似于github/gitlab等网站。没想到@会被转换成链接,所以我进行了编辑 :) - Darnuria

-2

*** 正如SirDarius在下面指出的那样,这实际上并不起作用。

使用T:AsRef<str>

impl<T: AsRef<str>> std::convert::TryFrom<T> for Instruction {
    type Error = InstructionParseError;    
    fn try_from(input: T) -> Result<Self, Self::Error> {
      let input: &str = input.as_ref();
      match input {
        "F" => Ok(Instruction::Forward),
        _ => unimplemented!(), // For brievity
     }
    }
}

1
这将是一个相当惯用的解决方案,但它与core中针对TryFrom的全局实现发生冲突:impl<T, U> TryFrom<U> for T where U: Into<T>;,因此无法编译。 - SirDarius
我总是遇到这种情况。 - NovaDenizen
由于孤儿规则是禁止的吗?只需阅读此问题,然后再次阅读ch10-02 trait - Darnuria

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接