我如何 return 实现中的特征以便我可以进行链式调用?
How can I return a trait from an implementation so I can chain calls?
我有几个实现的特征,我想 return 这个对象,这样我就可以链式调用。
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> RequestInfo {
self
}
}
struct LoggedOut {}
impl LoggedOut {
fn new() -> Box<RequestInfo> {
Box::new(LoggedOut {})
}
}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {
false
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> Box<RequestInfo> {
Box::new(LoggedIn { output: Vec::new() })
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {
true
}
fn put(&mut self, string: String) -> impl RequestInfo {
self.output.push(string);
self
}
}
fn main() {
let mut info = LoggedIn::new();
info.put("abc".to_string()).put("def".to_string());
}
我收到错误:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/main.rs:32:42
|
32 | fn put(&mut self, string: String) -> impl RequestInfo {
| ^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:4:9
|
3 | fn put(&mut self, string: String) -> RequestInfo {
| ----------- expected `(dyn RequestInfo + 'static)` because of return type
4 | self
| ^^^^ expected trait RequestInfo, found &mut Self
|
= note: expected type `(dyn RequestInfo + 'static)`
found type `&mut Self`
error[E0277]: the size for values of type `(dyn RequestInfo + 'static)` cannot be known at compilation time
--> src/main.rs:3:42
|
3 | fn put(&mut self, string: String) -> RequestInfo {
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn RequestInfo + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: the return type of a function must have a statically known size
唯一可行的方法是 Box
self,就像我在 new()
函数中所做的那样,但我不想通过链接创建任何额外的代码...这是无论如何真的只是一个方便。
返回 &mut Self
并使用 Box<impl RequestInfo>
几乎可以工作....除了我有一个函数 return 是 LoggedIn
对象或 LoggedOut
对象,所以这里是修改后的代码:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self {
self
}
}
struct LoggedOut {}
impl LoggedOut {
fn new() -> Box<impl RequestInfo> {
Box::new(LoggedOut {})
}
}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {
false
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> Box<impl RequestInfo> {
Box::new(LoggedIn { output: Vec::new() })
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {
true
}
fn put(&mut self, string: String) -> &mut Self {
self.output.push(string);
self
}
}
fn get(flag: bool) -> Box<impl RequestInfo> {
if flag {
return LoggedIn::new();
}
LoggedOut::new()
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
它给出了以下错误(在函数的前面它 returned 了一个 LoggedIn
对象):
error[E0308]: mismatched types
--> src/main.rs:42:5
|
42 | LoggedOut::new()
| ^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
|
= note: expected type `std::boxed::Box<impl RequestInfo>` (opaque type)
found type `std::boxed::Box<impl RequestInfo>` (opaque type)
现在进入最后一步:您会注意到 return Self
can not be used as trait objects 方法的特征。 link 可以解决您的问题:用 where Self: Sized
标记该方法,这样它就不会出现在您的特征对象上。但是你不能用特征对象进行链接。这可以通过在 Box<dyn RequestInfo>
上实现方法来解决——这不是特征对象,而是 Box
。所以,把这些放在一起:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self
where Self: Sized {
self.put_internal(string);
self
}
fn put_internal(&mut self, string: String) {}
}
impl RequestInfo for Box<dyn RequestInfo> {
fn logged_in(&self) -> bool {
self.as_ref().logged_in()
}
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {false}
}
struct LoggedIn {output: Vec<String>}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {true}
fn put_internal(&mut self, string: String) {
self.output.push(string);
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
您将不得不决定所有这些是否值得进行一些链接。
这个问题我想多了,你可以无视我之前的回答。该解决方案不必要地复杂。我有办法从 put
专注于 returning &mut Self
,即使根本没有要求。您可以从 put
方法 return &mut RequestInfo
就可以了。你付出的唯一代价是你不能再有 put
的默认实现。
pub trait RequestInfo {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo;
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
self
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
self.output.push(string);
self
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(false);
info.put("abc".to_string()).put("def".to_string());
}
我有几个实现的特征,我想 return 这个对象,这样我就可以链式调用。
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> RequestInfo {
self
}
}
struct LoggedOut {}
impl LoggedOut {
fn new() -> Box<RequestInfo> {
Box::new(LoggedOut {})
}
}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {
false
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> Box<RequestInfo> {
Box::new(LoggedIn { output: Vec::new() })
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {
true
}
fn put(&mut self, string: String) -> impl RequestInfo {
self.output.push(string);
self
}
}
fn main() {
let mut info = LoggedIn::new();
info.put("abc".to_string()).put("def".to_string());
}
我收到错误:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/main.rs:32:42
|
32 | fn put(&mut self, string: String) -> impl RequestInfo {
| ^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/main.rs:4:9
|
3 | fn put(&mut self, string: String) -> RequestInfo {
| ----------- expected `(dyn RequestInfo + 'static)` because of return type
4 | self
| ^^^^ expected trait RequestInfo, found &mut Self
|
= note: expected type `(dyn RequestInfo + 'static)`
found type `&mut Self`
error[E0277]: the size for values of type `(dyn RequestInfo + 'static)` cannot be known at compilation time
--> src/main.rs:3:42
|
3 | fn put(&mut self, string: String) -> RequestInfo {
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn RequestInfo + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: the return type of a function must have a statically known size
唯一可行的方法是 Box
self,就像我在 new()
函数中所做的那样,但我不想通过链接创建任何额外的代码...这是无论如何真的只是一个方便。
返回 &mut Self
并使用 Box<impl RequestInfo>
几乎可以工作....除了我有一个函数 return 是 LoggedIn
对象或 LoggedOut
对象,所以这里是修改后的代码:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self {
self
}
}
struct LoggedOut {}
impl LoggedOut {
fn new() -> Box<impl RequestInfo> {
Box::new(LoggedOut {})
}
}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {
false
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> Box<impl RequestInfo> {
Box::new(LoggedIn { output: Vec::new() })
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {
true
}
fn put(&mut self, string: String) -> &mut Self {
self.output.push(string);
self
}
}
fn get(flag: bool) -> Box<impl RequestInfo> {
if flag {
return LoggedIn::new();
}
LoggedOut::new()
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
它给出了以下错误(在函数的前面它 returned 了一个 LoggedIn
对象):
error[E0308]: mismatched types
--> src/main.rs:42:5
|
42 | LoggedOut::new()
| ^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
|
= note: expected type `std::boxed::Box<impl RequestInfo>` (opaque type)
found type `std::boxed::Box<impl RequestInfo>` (opaque type)
现在进入最后一步:您会注意到 return Self
can not be used as trait objects 方法的特征。 link 可以解决您的问题:用 where Self: Sized
标记该方法,这样它就不会出现在您的特征对象上。但是你不能用特征对象进行链接。这可以通过在 Box<dyn RequestInfo>
上实现方法来解决——这不是特征对象,而是 Box
。所以,把这些放在一起:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self
where Self: Sized {
self.put_internal(string);
self
}
fn put_internal(&mut self, string: String) {}
}
impl RequestInfo for Box<dyn RequestInfo> {
fn logged_in(&self) -> bool {
self.as_ref().logged_in()
}
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {false}
}
struct LoggedIn {output: Vec<String>}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {true}
fn put_internal(&mut self, string: String) {
self.output.push(string);
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
您将不得不决定所有这些是否值得进行一些链接。
这个问题我想多了,你可以无视我之前的回答。该解决方案不必要地复杂。我有办法从 put
专注于 returning &mut Self
,即使根本没有要求。您可以从 put
方法 return &mut RequestInfo
就可以了。你付出的唯一代价是你不能再有 put
的默认实现。
pub trait RequestInfo {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo;
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
self
}
}
struct LoggedIn {
output: Vec<String>,
}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
self.output.push(string);
self
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(false);
info.put("abc".to_string()).put("def".to_string());
}