将字符串克隆到特定的生命周期
Clone String to Specific Lifetime
我目前正在尝试用 Rust 编写一个小的命令行应用程序,但我遇到了生命周期的瓶颈。
extern crate clap;
use self::clap::{App, Arg};
use std::env;
impl<'p> Params<'p> {
fn get_username_arg<'r>() -> Arg<'r, 'r> {
let mut arg = Arg::with_name("Username")
.short("u")
.long("username")
.takes_value(true);
match env::var("USERNAME") {
Ok(username) => {
// How do I pass `username` to default_value?
arg.default_value(username)
}
Err(e) => arg.required(true),
}
}
// More code below...
}
问题是我试图将 username
传递给默认值方法,该方法需要生命周期为 'r
的 str
。我试过克隆,但我不知道如何告诉它克隆的生命周期是多少。我尝试了以下几行:
let cln = (&*username).clone::<'r>();
arg.default_value(username)
出于某种原因,它现在告诉我 username
的寿命不够长,尽管自从我克隆了数据后这应该无关紧要。
所以我的问题是,如何进行编译?
编辑:我想补充一点,除了生命周期参数之外,签名保持不变对我来说很重要。我不介意进行克隆等昂贵的操作来完成这项工作。
解释问题所在。
此处的解决方案是检索用户名(如果有),这样您就可以将其作为 String
参考。
let user_name = match env::var("USERNAME") {
Ok(user_name) => Some( user_name ),
Err(_) => None,
} ;
// Now we can take a reference on the user name String (if any) that can live
// long enough for the arg.
let arg = match user_name {
Some(ref name) => arg.default_value(name),
None => arg.required(true),
} ;
工作示例:
extern crate clap ;
use std::env;
use clap::* ;
fn main() {
let arg = Arg::with_name("Username")
.help("The user name")
.short("u")
.long("username")
.takes_value(true);
let user_name = match env::var("USERNAME") {
Ok(user_name) => Some(user_name),
Err(_) => None,
};
let arg = match user_name {
Some(ref name) => arg.default_value(name),
None => arg.required(true),
};
let app = App::new("Test").arg(arg);
let matches = app.get_matches();
match matches.value_of("username") {
Some(name) => println!("name: \"{}\"", name),
None => println!("no name :("),
}
}
Arg::default_value
接受一个 &str
作为参数,这意味着字符串没有存储在 Arg
中,而是存储在其他地方。所以 &str
值必须比保持引用的 Arg
长。如果您使用从 get_username_arg
中创建的 String
值获得的 &str
(username
就是这种情况),Arg
将比 &str
(将存在于 get_username_arg
之外,而 &str
仅存在于 Ok
块中),因此这会产生编译器错误。
一个选项是将默认用户名作为参数传递:
extern crate clap;
use self::clap::Arg;
use std::env;
pub struct Params;
impl Params {
fn get_username_arg(default: Option<&str>) -> Arg {
let arg = Arg::with_name("Username")
.short("u")
.long("username")
.takes_value(true);
if let Some(d) = default {
arg.default_value(d)
} else {
arg.required(true)
}
}
}
fn main() {
// type can be omitted
let username: Option<String> = env::var("USERNAME").ok();
// username.as_ref() produces Option<&String>
// map(String::as_str) produces Some(&str) from Some(&String)
// or None from None
let arg = Params::get_username_arg(username.as_ref().map(String::as_str));
}
注意 username
在 arg
之前声明,所以 username
比 arg
长。
I'd like to add that its important to me that the signature stays the same aside from the lifetime parameters. I don't mind doing expensive operations such as cloning to make this work.
您没有显示 Params
定义,但它似乎只是某些功能的 "name space"。如果是这种情况,您可以更改这些函数以接收 &self
作为参数(我知道这是在更改签名,但创建 args 的逻辑将保留在 Params
中),并存储 username
在 Params
中:
extern crate clap;
use self::clap::Arg;
use std::env;
pub struct Params {
username: Option<String>,
}
impl Params {
fn new() -> Params {
Params {
username: env::var("USERNAME").ok(),
}
}
fn get_username_arg(&self) -> Arg {
let arg = Arg::with_name("Username")
.short("u")
.long("username")
.takes_value(true);
if let Some(d) = self.username.as_ref().map(String::as_str) {
arg.default_value(d)
} else {
arg.required(true)
}
}
}
fn main() {
let params = Params::new();
let arg = params.get_username_arg();
}
,但我想讨论非工作代码的某些方面。
让我们从函数签名开始:
fn get_username_arg<'r>() -> Arg<'r, 'r> {
这表示 "for any lifetime that the caller of this function picks, I will return an Arg
that contains references that will last that long"。这是一个很难坚持的承诺,因为调用者可以请求满足 'static
生命周期的东西,这个值比 main
的调用持续 长!事实上,履行 "any lifetime" 义务的唯一方法是 return 某事 'static
。
这是一个很好的迹象,表明将要出现问题。另见 ,它将这种情况显示为构造函数。许多人跳转到 return 和 String
以及 &str
,所以这个答案也可能使这条道路短路。 ^_^
username
doesn't live long enough, even though it shouldn't matter since I cloned the data.
username
有一个非常具体的生命周期,而且是有限的。如果您查看一段代码,通常可以直接找出对象的生命周期:它是变量在不移动的情况下所在的块的范围。在您的示例中,username
仅存在于匹配臂 Ok(username) => { // }
的块中。一旦该块退出,该值就会被销毁。
clone
in this case has a signature of <'s>clone() -> &'s str
if you remove elisions (and reify Self
) according to my very limited understanding of Rust in general.
env::var
returns a Result<String, VarError>
,你访问 Ok
变体,使 username
成为 String
。 String
implementation of clone
需要 &String
,return 需要 String
。我不确定 -> &'s str
的来源。
So if I clone with clone::<'r>()
it should force the lifetime...
这是一个非常的常见错误。查看 (and maybe ) 了解一些背景信息。您 不能 改变某些东西的生命周期,除非重写您的代码以使引用的值具有更大的范围。生命周期语法反映了变量的生命周期,它不控制它。 "force" 一生没有(安全)方法。
(&*username).clone
has that signature I mean
如果我们取消引用并重新引用 String
,我们最终会得到 &str
。 &str
的生命周期对应于 String
的生命周期。这是有道理的,因为 &str
只是指向 String
。当 String
被释放时,&str
将指向不再处于有效状态的内存。
我目前正在尝试用 Rust 编写一个小的命令行应用程序,但我遇到了生命周期的瓶颈。
extern crate clap;
use self::clap::{App, Arg};
use std::env;
impl<'p> Params<'p> {
fn get_username_arg<'r>() -> Arg<'r, 'r> {
let mut arg = Arg::with_name("Username")
.short("u")
.long("username")
.takes_value(true);
match env::var("USERNAME") {
Ok(username) => {
// How do I pass `username` to default_value?
arg.default_value(username)
}
Err(e) => arg.required(true),
}
}
// More code below...
}
问题是我试图将 username
传递给默认值方法,该方法需要生命周期为 'r
的 str
。我试过克隆,但我不知道如何告诉它克隆的生命周期是多少。我尝试了以下几行:
let cln = (&*username).clone::<'r>();
arg.default_value(username)
出于某种原因,它现在告诉我 username
的寿命不够长,尽管自从我克隆了数据后这应该无关紧要。
所以我的问题是,如何进行编译?
编辑:我想补充一点,除了生命周期参数之外,签名保持不变对我来说很重要。我不介意进行克隆等昂贵的操作来完成这项工作。
此处的解决方案是检索用户名(如果有),这样您就可以将其作为 String
参考。
let user_name = match env::var("USERNAME") {
Ok(user_name) => Some( user_name ),
Err(_) => None,
} ;
// Now we can take a reference on the user name String (if any) that can live
// long enough for the arg.
let arg = match user_name {
Some(ref name) => arg.default_value(name),
None => arg.required(true),
} ;
工作示例:
extern crate clap ;
use std::env;
use clap::* ;
fn main() {
let arg = Arg::with_name("Username")
.help("The user name")
.short("u")
.long("username")
.takes_value(true);
let user_name = match env::var("USERNAME") {
Ok(user_name) => Some(user_name),
Err(_) => None,
};
let arg = match user_name {
Some(ref name) => arg.default_value(name),
None => arg.required(true),
};
let app = App::new("Test").arg(arg);
let matches = app.get_matches();
match matches.value_of("username") {
Some(name) => println!("name: \"{}\"", name),
None => println!("no name :("),
}
}
Arg::default_value
接受一个 &str
作为参数,这意味着字符串没有存储在 Arg
中,而是存储在其他地方。所以 &str
值必须比保持引用的 Arg
长。如果您使用从 get_username_arg
中创建的 String
值获得的 &str
(username
就是这种情况),Arg
将比 &str
(将存在于 get_username_arg
之外,而 &str
仅存在于 Ok
块中),因此这会产生编译器错误。
一个选项是将默认用户名作为参数传递:
extern crate clap;
use self::clap::Arg;
use std::env;
pub struct Params;
impl Params {
fn get_username_arg(default: Option<&str>) -> Arg {
let arg = Arg::with_name("Username")
.short("u")
.long("username")
.takes_value(true);
if let Some(d) = default {
arg.default_value(d)
} else {
arg.required(true)
}
}
}
fn main() {
// type can be omitted
let username: Option<String> = env::var("USERNAME").ok();
// username.as_ref() produces Option<&String>
// map(String::as_str) produces Some(&str) from Some(&String)
// or None from None
let arg = Params::get_username_arg(username.as_ref().map(String::as_str));
}
注意 username
在 arg
之前声明,所以 username
比 arg
长。
I'd like to add that its important to me that the signature stays the same aside from the lifetime parameters. I don't mind doing expensive operations such as cloning to make this work.
您没有显示 Params
定义,但它似乎只是某些功能的 "name space"。如果是这种情况,您可以更改这些函数以接收 &self
作为参数(我知道这是在更改签名,但创建 args 的逻辑将保留在 Params
中),并存储 username
在 Params
中:
extern crate clap;
use self::clap::Arg;
use std::env;
pub struct Params {
username: Option<String>,
}
impl Params {
fn new() -> Params {
Params {
username: env::var("USERNAME").ok(),
}
}
fn get_username_arg(&self) -> Arg {
let arg = Arg::with_name("Username")
.short("u")
.long("username")
.takes_value(true);
if let Some(d) = self.username.as_ref().map(String::as_str) {
arg.default_value(d)
} else {
arg.required(true)
}
}
}
fn main() {
let params = Params::new();
let arg = params.get_username_arg();
}
让我们从函数签名开始:
fn get_username_arg<'r>() -> Arg<'r, 'r> {
这表示 "for any lifetime that the caller of this function picks, I will return an Arg
that contains references that will last that long"。这是一个很难坚持的承诺,因为调用者可以请求满足 'static
生命周期的东西,这个值比 main
的调用持续 长!事实上,履行 "any lifetime" 义务的唯一方法是 return 某事 'static
。
这是一个很好的迹象,表明将要出现问题。另见 String
以及 &str
,所以这个答案也可能使这条道路短路。 ^_^
username
doesn't live long enough, even though it shouldn't matter since I cloned the data.
username
有一个非常具体的生命周期,而且是有限的。如果您查看一段代码,通常可以直接找出对象的生命周期:它是变量在不移动的情况下所在的块的范围。在您的示例中,username
仅存在于匹配臂 Ok(username) => { // }
的块中。一旦该块退出,该值就会被销毁。
clone
in this case has a signature of<'s>clone() -> &'s str
if you remove elisions (and reifySelf
) according to my very limited understanding of Rust in general.
env::var
returns a Result<String, VarError>
,你访问 Ok
变体,使 username
成为 String
。 String
implementation of clone
需要 &String
,return 需要 String
。我不确定 -> &'s str
的来源。
So if I clone with
clone::<'r>()
it should force the lifetime...
这是一个非常的常见错误。查看
(&*username).clone
has that signature I mean
如果我们取消引用并重新引用 String
,我们最终会得到 &str
。 &str
的生命周期对应于 String
的生命周期。这是有道理的,因为 &str
只是指向 String
。当 String
被释放时,&str
将指向不再处于有效状态的内存。