简体   繁体   English

如何实现功能特征

[英]How to implement a trait for a function

I have the following code 我有以下代码

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);

It doesn't compile. 它不会编译。 It complains that hazard_predicate doesn't implement a particular trait. 它抱怨azar_predicate没有实现特定的特征。

Here is the error message 这是错误消息

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`.

So How do I implement that trait for my predicate function? 那么,如何为我的谓词功能实现该特征呢?

Let's look at the documentation for the types and traits in question. 让我们看一下有关类型和特征的文档。 Usually the required traits are implemented automatically on all the types where it is possible, and, in fact, if the type in question is not your own, the trait has to be implemented by the library. 通常情况下,需要的性状是对所有在有可能的类型自动执行,并且,事实上,如果有问题的类型是不是你自己的,性状必须由图书馆来实施。 So, first of all we check the assert_cmd docs to see what types can be used here. 因此,首先我们检查assert_cmd文档,以了解此处可以使用哪些类型。

There are two implementations which can be of interest for us: 我们可能会对以下两种实现感兴趣:

impl<P> IntoOutputPredicate<StrOutputPredicate<P>> for P
where
    P: Predicate<str>
impl<P> IntoOutputPredicate<P> for P
where
    P: Predicate<[u8]>

Let's see now, what is the Predicate . 现在让我们看看什么是Predicate This ends in the predicates-core crate, so it seems that at least some of the items from the predicates crate (based on this core) will be possible to use. 这以predicates-core板箱结尾,因此似乎可以使用predicates词条板箱中的至少某些项目(基于此核心)。

Now, let's try the other way round - look through the docs for predicate::function : 现在,让我们尝试另一种方式-浏览文档中的predicate::function

pub fn function<F, T>(function: F) -> FnPredicate<F, T> 
where
    F: Fn(&T) -> bool,
    T: ?Sized, 

Well then, we've got the type FnPredicate mentioned in the error message, so what traits are implemented by it? 那么,我们在错误消息中提到了FnPredicate类型,那么它实现哪些特征

impl<F, T> Predicate<T> for FnPredicate<F, T>
where
    F: Fn(&T) -> bool,
    T: ?Sized, 

Here it is! 这里是! You've passed a closure taking &String , so the T in this definition is inferred to be String , ie the implemented trait is Predicate<String> . 您已经传递了带有&String的闭包,因此此定义中的T推断为String ,即实现的特征是Predicate<String>

Now, if you recall the first part, you'll see that there is no Predicate<String> there in implementations! 现在,如果您回想起第一部分,您会发现实现中没有Predicate<String>

How to resolve this? 如何解决呢?

I see two possibilities, as for now: 就目前而言,我看到两种可能性:

  1. You can use the second implementation and make your predicate take reference to a byte slice &[u8] . 您可以使用第二种实现,并使您的谓词引用字节切片&[u8] I can't test it with the library itself, since it isn't on the playground, but if I make this change just in closure, I 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]`

Fortunately, this is fairly easily fixed by changing string literals to byte strings ( playground ): 幸运的是,通过将字符串文字更改为字节字符串( parker ),可以很容易地解决此问题:

let _ = |x: &[u8]| {
    x == b"You got it right!" || x == b"You got it wrong!"
};

Note that I also took advantage of Clippy hints to simplify the code in question (on playground it is under Tools button on the right side). 请注意,我还利用了Clippy提示来简化相关代码(在操场上,它位于右侧的“工具”按钮下)。

Now, if you pass this closure into predicate::function , all should work fine. 现在,如果您将此闭包传递给predicate::function ,那么一切都可以正常工作。

  1. Another way is to use the first implementation - you can see that Predicate<str> , ie function predicate receiving &str , is also supported, although in a bit more complex way. 另一种方法是使用第一个实现-您可以看到Predicate<str> (即,函数谓词接收&str )也受支持,尽管有点复杂。 But for now this doesn't seem to be a problem, since the trait is implemented anyway - that's just one internal layer of indirection, but this is not your problem ( assert_cmd crate should handle this itself). 但是现在看来这似乎不是问题,因为无论如何都实现了特征-这只是间接的一个内部层,但这不是您的问题( assert_cmd板条箱应该自己处理)。 This code, in particular, compiles well: 这段代码尤其可以很好地编译:
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);
}

Side note 边注

There is a long-standing question here describing why this is bad to have the functions require &String (or &Vec , or &Box - a reference to the owned container, it is). 还有这里的长期问题,说明为什么这是不好具备的功能要求&String (或&Vec ,或&Box -到所属容器的引用,它是)。 In short - you can replace &String by &str , and this will not be a restriction. 简而言之-您可以将&String替换为&str ,并且这不是限制。 Of course, library authors know that too and usually force you to have the most general way, where you have to work with the least indirection possible. 当然,库作者也知道这一点,通常会迫使您采用最通用的方式,即您必须使用最少的间接方式进行工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM