有没有办法为 &str 实现 Into<&str> 或 From<T> ?

not*_*lds 10 rust

正在用 Rust 编写一些代码,尝试使用(否则相当不错的) crate 来定义 CLI clap,但遇到了一个相当关键的问题。App接受 an的方法Into<&'help str>,我一直无法找到实现此特征的方法。

事实上,据我了解,这是绝对无法实现的:

struct JustWorkDamnIt {
    string: String
}

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

...产生:

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
Run Code Online (Sandbox Code Playgroud)

然而有趣的是,返回一个文字编译得很好(我认为这就是为什么clap不介意使用这个特性)。大概这是因为文字被编译到内存的某个静态区域,因此不属于该函数:

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
Run Code Online (Sandbox Code Playgroud)

但是,我的意思是,肯定有办法实现这个特性并返回动态字符串吗?也许巧妙地使用了 Box<> 之类的东西,idk。我相信我已经尝试了所有我能想到的事情。

如果没有办法,那么这对于 Rust 来说似乎是一个非常明显的缺陷——可以在函数头中声明和使用的特征,但实际上无法有意义地实现(返回文字没有多大意义)。如果事实确实如此,我将在 rust-lang 存储库上为此流程创建一个问题,但首先我想在这里对我的发现进行健全性检查。


UPD:感谢您的评论,让我更深入地思考这个问题。

问题似乎与生命周期有关。我很抱歉没有显示完整的代码,我认为我分享的代码片段足以描述问题,但事后看来,上下文对于 Rust 的生命周期很重要,这确实是有道理的。

我确实找到了针对这个特定问题实例的“解决方案”。由于相关代码在每个可执行文件启动时只会运行一次,因此我可以Box::leak就此&'static str结束。不过,我想知道是否有一个更通用的解决方案可用于经常创建的动态字符串。

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

目前我在这里面临两点困惑:

  • 为什么没有impl From<String> for &str?编译器声称存在一个impl From<String> for &mut str,但我没有看到这里的重要性mut
  • ...如果有充分的理由不这样做,那么以某种方式阻止在库的公共 API 中impl From<String> for &str使用 是否有意义?Into<&str>

或者问题可能出在我的 build_args_parser 函数上,而就 Rust 而言,它不是一个将工作卸载给它的选项?

小智 4

似乎您正在尝试将 a 转换String&'a str. 你可以这样做:

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
}
Run Code Online (Sandbox Code Playgroud)

这是我们要调用的函数的签名:

pub fn about<S: Into<&'b str>>(self, about: S) -> Self
Run Code Online (Sandbox Code Playgroud)

所以about参数必须实现 Trait Into<&'b str>。据此std::convert::Into,我们知道确实&'b str实现了trait Into<&'b str>。所以现在我们只需要一种方法来转换String&'b str. 告诉std::string::String我们有两种方法:使用s.as_str()&*s