如何为函数实现特征
How to implement a trait for a function
我有以下代码
let hazard_predicate = predicate::function(|x: &String| {
if (x == "You got it right!" || x == "You got it wrong!") {
return true;
} else {
return false;
}
});
let mut cmd = Command::cargo_bin("rust-starter").expect("Calling binary failed");
cmd.arg("hazard").assert().stdout(hazard_predicate);
它不编译。它抱怨 hazard_predicate 没有实现特定的特征。
这是错误信息
error[E0277]: the trait bound
`predicates::function::FnPredicate<[closure@core/tests/test_cli.rs:31:48: 37:6], std::string::String>: assert_cmd::assert::IntoOutputPredicate<_>` is not satisfied
--> core/tests/test_cli.rs:39:32
|
39 | cmd.arg("hazard").assert().stdout(hazard_predicate);
| ^^^^^^ the trait `assert_cmd::assert::IntoOutputPredicate<_>` is not implemented for `predicates::function::FnPredicate<[closure@core/tests/test_cli.rs:31:48: 37:6], std::string::String>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
那么如何为我的谓词函数实现该特征?
让我们看看相关类型和特征的文档。通常所需的特征会在所有可能的类型上自动实现,事实上,如果所讨论的类型不是您自己的,特征 必须 由库实现.所以,首先我们检查 assert_cmd
docs 看看这里可以使用什么类型。
我们可能会对两种实现感兴趣:
impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P
where
P: Predicate<str>
impl<P> IntoOutputPredicate<P> for P
where
P: Predicate<[u8]>
让我们现在看看,what is the Predicate
。这在 predicates-core
箱子中结束,因此似乎至少可以使用 predicates
箱子(基于此核心)中的某些项目。
现在,让我们尝试反过来 - 查看 docs for predicate::function
:
pub fn function<F, T>(function: F) -> FnPredicate<F, T>
where
F: Fn(&T) -> bool,
T: ?Sized,
那么,我们得到了错误消息中提到的类型 FnPredicate
,所以 what traits are implemented 是吗?
impl<F, T> Predicate<T> for FnPredicate<F, T>
where
F: Fn(&T) -> bool,
T: ?Sized,
在这里!您已经通过了一个采用 &String
的闭包,因此该定义中的 T
被推断为 String
,即实现的特征是 Predicate<String>
.
现在,如果您回想一下第一部分,您会发现在实现中没有 Predicate<String>
!
如何解决这个问题?
目前我看到两种可能:
- 您可以使用第二种实现并使您的谓词引用字节片
&[u8]
。我无法使用库本身对其进行测试,因为它不在操场上,但如果我只是在关闭时进行此更改,我 immediately get the error:
error[E0277]: can't compare `[u8]` with `str`
--> src/lib.rs:3:15
|
3 | if (x == "You got it right!" || x == "You got it wrong!") {
| ^^ no implementation for `[u8] == str`
|
= help: the trait `std::cmp::PartialEq<str>` is not implemented for `[u8]`
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&str>` for `&[u8]`
幸运的是,通过将字符串文字更改为字节字符串 (playground) 可以很容易地解决这个问题:
let _ = |x: &[u8]| {
x == b"You got it right!" || x == b"You got it wrong!"
};
请注意,我还利用 Clippy 提示来简化有问题的代码(在操场上,它位于右侧的“工具”按钮下)。
现在,如果将此闭包传递给 predicate::function
,一切都应该可以正常工作。
- 另一种方法是使用第一个实现 - 您可以看到
Predicate<str>
,即函数谓词接收 &str
,也受支持,尽管方式有点复杂。但现在这似乎不是问题,因为无论如何实现了 trait - 这只是一个内部间接层,但这不是你的问题(assert_cmd
crate 应该自己处理这个)。尤其是这段代码编译得很好:
use assert_cmd::{assert::OutputAssertExt, cargo::CommandCargoExt};
use predicates::prelude::*;
use std::process::Command;
fn main() {
let hazard_predicate =
predicate::function(|x: &str| x == "You got it right!" || x == "You got it wrong!");
let mut cmd = Command::cargo_bin("rust-starter").expect("Calling binary failed");
cmd.arg("hazard").assert().stdout(hazard_predicate);
}
旁注
有 描述了为什么函数需要 &String
(或 &Vec
,或 &Box
- 对拥有的容器的引用是不好的,它是)。简而言之 - 您可以将 &String
替换为 &str
,这将不是限制。当然,库作者也知道这一点,通常会强制您采用最通用的方式,在这种方式中您必须使用尽可能少的间接方式。
我有以下代码
let hazard_predicate = predicate::function(|x: &String| {
if (x == "You got it right!" || x == "You got it wrong!") {
return true;
} else {
return false;
}
});
let mut cmd = Command::cargo_bin("rust-starter").expect("Calling binary failed");
cmd.arg("hazard").assert().stdout(hazard_predicate);
它不编译。它抱怨 hazard_predicate 没有实现特定的特征。
这是错误信息
error[E0277]: the trait bound
`predicates::function::FnPredicate<[closure@core/tests/test_cli.rs:31:48: 37:6], std::string::String>: assert_cmd::assert::IntoOutputPredicate<_>` is not satisfied
--> core/tests/test_cli.rs:39:32
|
39 | cmd.arg("hazard").assert().stdout(hazard_predicate);
| ^^^^^^ the trait `assert_cmd::assert::IntoOutputPredicate<_>` is not implemented for `predicates::function::FnPredicate<[closure@core/tests/test_cli.rs:31:48: 37:6], std::string::String>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
那么如何为我的谓词函数实现该特征?
让我们看看相关类型和特征的文档。通常所需的特征会在所有可能的类型上自动实现,事实上,如果所讨论的类型不是您自己的,特征 必须 由库实现.所以,首先我们检查 assert_cmd
docs 看看这里可以使用什么类型。
我们可能会对两种实现感兴趣:
impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P
where
P: Predicate<str>
impl<P> IntoOutputPredicate<P> for P
where
P: Predicate<[u8]>
让我们现在看看,what is the Predicate
。这在 predicates-core
箱子中结束,因此似乎至少可以使用 predicates
箱子(基于此核心)中的某些项目。
现在,让我们尝试反过来 - 查看 docs for predicate::function
:
pub fn function<F, T>(function: F) -> FnPredicate<F, T>
where
F: Fn(&T) -> bool,
T: ?Sized,
那么,我们得到了错误消息中提到的类型 FnPredicate
,所以 what traits are implemented 是吗?
impl<F, T> Predicate<T> for FnPredicate<F, T>
where
F: Fn(&T) -> bool,
T: ?Sized,
在这里!您已经通过了一个采用 &String
的闭包,因此该定义中的 T
被推断为 String
,即实现的特征是 Predicate<String>
.
现在,如果您回想一下第一部分,您会发现在实现中没有 Predicate<String>
!
如何解决这个问题?
目前我看到两种可能:
- 您可以使用第二种实现并使您的谓词引用字节片
&[u8]
。我无法使用库本身对其进行测试,因为它不在操场上,但如果我只是在关闭时进行此更改,我 immediately get the error:
error[E0277]: can't compare `[u8]` with `str`
--> src/lib.rs:3:15
|
3 | if (x == "You got it right!" || x == "You got it wrong!") {
| ^^ no implementation for `[u8] == str`
|
= help: the trait `std::cmp::PartialEq<str>` is not implemented for `[u8]`
= note: required because of the requirements on the impl of `std::cmp::PartialEq<&str>` for `&[u8]`
幸运的是,通过将字符串文字更改为字节字符串 (playground) 可以很容易地解决这个问题:
let _ = |x: &[u8]| {
x == b"You got it right!" || x == b"You got it wrong!"
};
请注意,我还利用 Clippy 提示来简化有问题的代码(在操场上,它位于右侧的“工具”按钮下)。
现在,如果将此闭包传递给 predicate::function
,一切都应该可以正常工作。
- 另一种方法是使用第一个实现 - 您可以看到
Predicate<str>
,即函数谓词接收&str
,也受支持,尽管方式有点复杂。但现在这似乎不是问题,因为无论如何实现了 trait - 这只是一个内部间接层,但这不是你的问题(assert_cmd
crate 应该自己处理这个)。尤其是这段代码编译得很好:
use assert_cmd::{assert::OutputAssertExt, cargo::CommandCargoExt};
use predicates::prelude::*;
use std::process::Command;
fn main() {
let hazard_predicate =
predicate::function(|x: &str| x == "You got it right!" || x == "You got it wrong!");
let mut cmd = Command::cargo_bin("rust-starter").expect("Calling binary failed");
cmd.arg("hazard").assert().stdout(hazard_predicate);
}
旁注
有 &String
(或 &Vec
,或 &Box
- 对拥有的容器的引用是不好的,它是)。简而言之 - 您可以将 &String
替换为 &str
,这将不是限制。当然,库作者也知道这一点,通常会强制您采用最通用的方式,在这种方式中您必须使用尽可能少的间接方式。