我实现了这个小函数,它返回对枚举值的引用。这很好用:
pub enum Entry {
COMMENT,
NUM(Option<String>, f64),
STR(Option<String>, String),
VNUM(Option<String>, Vec<f64>),
VSTR(Option<String>, Vec<String>),
}
pub fn get_value<'b>(k: &str, entity: &'b [Entry]) -> Option<&'b str> {
entity
.iter()
.filter_map(|x| match x {
&Entry::STR(ref key, ref v) => if key.as_ref().unwrap().as_str() == k {
Some(v.as_str())
} else {
None
},
_ => None,
})
.next()
}
fn main() {
let v = vec![
Entry::STR(Some("foo".to_string()), "bar".to_string()),
Entry::NUM(Some("baz".to_string()), 1234f64),
];
let x: Option<&str> = get_value("foo", &v);
}
为了灌输一些多态性,我想把它转移到一个特性,以便我可以为不同的类型调用它
pub trait GetValue<T> {
fn get_value<'a>(k: &str, entity: &'a [Entry]) -> Option<&'a str>;
}
impl<'a> GetValue<&'a str> for &'a [Entry] {
fn get_value(k: &str, entity: &'a [Entry]) -> Option<&'a str> {
entity
.iter()
.filter_map(|x| match x {
&Entry::STR(ref key, ref v) => if key.as_ref().unwrap().as_str() == k {
Some(v.as_str())
} else {
None
},
_ => None,
})
.next()
}
}
但是尽管没有故意更改生命周期规范,但仍会出现以下错误。我错过了什么?
error[E0308]: method not compatible with trait
--> src/main.rs:14:5
|
14 | fn get_value(k: &str, entity: &'a [Entry]) -> Option<&'a str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `fn(&str, &'a [Entry]) -> std::option::Option<&'a str>`
found type `fn(&str, &'a [Entry]) -> std::option::Option<&'a str>`
note: the lifetime 'a as defined on the method body at 14:5...
--> src/main.rs:14:5
|
14 | fn get_value(k: &str, entity: &'a [Entry]) -> Option<&'a str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 13:1
--> src/main.rs:13:1
|
13 | impl<'a> GetValue<&'a str> for &'a [Entry] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: method not compatible with trait
--> src/main.rs:14:5
|
14 | fn get_value(k: &str, entity: &'a [Entry]) -> Option<&'a str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `fn(&str, &'a [Entry]) -> std::option::Option<&'a str>`
found type `fn(&str, &'a [Entry]) -> std::option::Option<&'a str>`
note: the lifetime 'a as defined on the impl at 13:1...
--> src/main.rs:13:1
|
13 | impl<'a> GetValue<&'a str> for &'a [Entry] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the method body at 14:5
--> src/main.rs:14:5
|
14 | fn get_value(k: &str, entity: &'a [Entry]) -> Option<&'a str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
答案 0 :(得分:1)
通过在&'a [Entry]
方法的签名中分别用&'a str
和Self
替换T
和get_value
,可以消除特征中的显式生命周期定义。因此,GetValue
的定义独立于&'a [Entry]
和&'a str
类型,这些类型特定于&'a [Entry]
的具体实现。作为副作用,您的终身问题将会消失。
pub trait GetValue<T> {
fn get_value(self, k: &str) -> Option<T>;
}
impl<'a> GetValue<&'a str> for &'a [Entry] {
fn get_value(self, k: &str) -> Option<&'a str> {
self.iter()
.filter_map(|x| match x {
&Entry::STR(ref key, ref v) =>
if key.as_ref().unwrap().as_str() == k {
Some(v.as_str())
} else {
None
},
_ => None,
})
.next()
}
}
这样,get_value
消费self
。在&'a [Entry]
的实施中,方法get_value
会使用&'a [Entry]
类型的内容。不可变引用是Copy
,因此在此实现中get_value
实际上只使用副本(&'a [Entry]
类型的内容在调用get_value
之后仍然可用。
GetValue
也可以针对非Copy
的内容实施。在这种类型的实例上调用get_value
将使用此实例。如果您希望get_value
在这方面更具限制性,可以让&'a self
作为参数而不是self
。这需要在您的特征上明确生存'a
:
pub trait GetValue<'a, T> {
fn get_value(&'a self, k: &str) -> Option<T>;
}
impl<'a> GetValue<'a, &'a str> for [Entry] {
fn get_value(&'a self, k: &str) -> Option<&'a str> { ... }
}
答案 1 :(得分:0)
使用相关生命周期定义特征:
pub trait GetValue<'c,T> {
fn get_value<'a : 'c>(&'c self, k : &str, entity : &'a [Entry]) -> Option<T>;
}
然后执行告诉Rust返回类型依赖于self
而不是entity
impl<'c> GetValue<'c,&'c str> for &'c [Entry] {
fn get_value<'a : 'c>(&'c self, k : &str, entity : &'a [Entry]) -> Option<&'c str> {
entity
.iter()
.filter_map(|x| match x {
&Entry::STR(ref key,ref v) => if key.as_ref().unwrap().as_str() == k { Some(v.as_str()) } else { None },
_ => None
})
.next()
}
}