简体   繁体   English

有什么方法可以实现 Into&lt;&amp;str&gt; 或 From<T> 对于 &amp;str?

[英]Is there any way to implement Into<&str> or From<T> for &str?

Was writing some code in Rust trying to define a CLI, using the (otherwise pretty great) crate clap , and run into a rather critical issue.正在用 Rust 编写一些代码,试图定义一个 CLI,使用(否则非常棒) crate clap ,并遇到了一个相当关键的问题。 Methods of App accept an Into<&'help str> , and i've been unable to find a way to implement this trait. App方法接受Into<&'help str> ,我一直无法找到实现此特征的方法。

Indeed from what i understand, it is absolutely unimplementable:事实上,据我所知,这是绝对无法实现的:

struct JustWorkDamnIt {
    string: String
}

impl From<JustWorkDamnIt> for &str {
    fn from(arg: JustWorkDamnIt) -> Self {
        return arg.string.as_str()
    }
}

...which yields: ...产生:

error[E0515]: cannot return value referencing local data `arg.string`
  --> src/cmd/interactive.rs:25:16
   |
25 |         return arg.string.as_str()
   |                ----------^^^^^^^^^
   |                |
   |                returns a value referencing data owned by the current function
   |                `arg.string` is borrowed here

Interestingly enough, however, returning a literal compiles just fine (which i reckon is why clap doesn't mind using this trait).然而,有趣的是,返回一个文字编译就好了(我认为这就是为什么clap不介意使用这个特性)。 Presumably that's because the literal is compiled to some static region of memory and therefore isn't owned by the function:大概是因为文字被编译到某个静态内存区域,因此不属于该函数:

impl From<JustWorkDamnIt> for &str {
    fn from(arg: JustWorkDamnIt) -> Self {
        return "literal"
    }
}

But, i mean, surely there's a way to implement this trait and return dynamic strings?但是,我的意思是,肯定有一种方法可以实现此特征并返回动态字符串吗? Maybe some clever use of Box<> or something, idk.也许巧妙地使用 Box<> 之类的,idk。 I believe i've tried all the things i could think of.我相信我已经尝试了所有我能想到的事情。

And if there isn't a way, then this seems like a pretty glaring flaw for Rust - traits which can be declared and used in function headers, but cannot be actually implemented meaningfully (there's not much of a point in returning a literal).如果没有办法,那么这对于 Rust 来说似乎是一个非常明显的缺陷 - 可以在函数头中声明和使用的特性,但实际上不能有意义地实现(返回文字没有多大意义)。 If this turns out to be the case i'll create an issue on the rust-lang repository for this flow, but first i wanted to sanity-check my findings here.如果结果确实如此,我将在 rust-lang 存储库上为此流程创建一个问题,但首先我想在这里检查我的发现。


UPD: Thanks for the comments, made me think more in-depth about this issue. UPD:感谢您的评论,让我更深入地思考这个问题。

The problem has to do with lifetimes, it seems.问题似乎与生命有关。 I apologize for not showing the entire code, i thought the snippets i shared would describe the problem sufficiently, but in hindsight it does make sense that the context would be important with Rust's lifetimes at play.我很抱歉没有展示整个代码,我认为我分享的片段会充分描述问题,但事后看来,上下文对 Rust 的生命周期很重要确实是有道理的。

I did find a "solution" for this particular instance of the problem.我确实为这个特定的问题实例找到了“解决方案”。 Since the code in question will only run once per executable start, i can just Box::leak the &'static str and call it a day.由于有问题的代码在每个可执行文件启动时只会运行一次,我可以只使用Box::leak &'static str并将其称为一天。 Still, i would like to figure out if there's a more general solution which could be used for often-created dynamic strings.不过,我想弄清楚是否有更通用的解决方案可用于经常创建的动态字符串。

impl Cmd for InteractiveCmd {
    fn build_args_parser<'a, 'b>(&'b self, builder: App<'a>) -> App<'a> {
        // leak() works here but i'm curious if there's a better way
        let staticStr : &'static str = Box::leak(Box::from(format!("Interactive {} shell", APPNAME).as_str()));
        let rv = builder
            // pub fn about<S: Into<&'b str>>(mut self, about: S) -> Self
            .about(staticStr) 
            .version("0.1");
        return rv;
    }
}

fn main() {
    let interactive = InteractiveCmd::new();
    let mut app = App::new(APPNAME)
        .version(APPVER)
        .author(AUTHORS)
      .subcommand(interactive.build_args_parser(App::new("interactive")));
}

Currently i am faced with 2 points of confusion here:目前我在这里面临两个困惑点:

  • Why is there no impl From<String> for &str ?为什么impl From<String> for &str没有impl From<String> for &str The compiler claims that one exists for impl From<String> for &mut str , and i'm not seeing the importance of mut here.编译器声称impl From<String> for &mut str存在一个,我在这里没有看到mut的重要性。
  • ...and if there is a good reason to not impl From<String> for &str , would it make sense to somehow discourage the usage of Into<&str> in the public APIs of libraries? ...如果有充分的理由不impl From<String> for &str ,那么以某种方式阻止在库的公共 API 中使用Into<&str>是否有意义?

Or maybe the issue is with my build_args_parser function and it's just not an option to offload the work to it as far as Rust is concerned?或者也许问题出在我的 build_args_parser 函数上,就 Rust 而言,它不是将工作卸载给它的选项?

Seems like you're trying to convert a String into a &'a str .似乎您正在尝试将String转换为&'a str You can do it like this:你可以这样做:

use clap::App;

fn main() {
    let s = format!("Interactive {} shell", "Testing");
    let app = App::new("Testing")
        .about(&*s); // or `.about(s.as_str());` it's the same
}

Here's the signature of the function that we want to call:这是我们要调用的函数的签名:

pub fn about<S: Into<&'b str>>(self, about: S) -> Self

So the about parameter must implement trait Into<&'b str> .所以about参数必须实现 trait Into<&'b str> According to std::convert::Into , we know that &'b str does implement trait Into<&'b str> .根据std::convert::Into ,我们知道&'b str确实实现了特征Into<&'b str> So now we just need a way to convert String into &'b str .所以现在我们只需要一种方法将String转换为&'b str The std::string::String tell us that there are two ways: use either s.as_str() or &*s . std::string::String告诉我们有两种方法:使用s.as_str()&*s

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM