簡體   English   中英

如何實現功能特征

[英]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);

它不會編譯。 它抱怨azar_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文檔,以了解此處可以使用哪些類型。

我們可能會對以下兩種實現感興趣:

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

現在讓我們看看什么是Predicate 這以predicates-core板箱結尾,因此似乎可以使用predicates詞條板箱中的至少某些項目(基於此核心)。

現在,讓我們嘗試另一種方式-瀏覽文檔中的predicate::function

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

那么,我們在錯誤消息中提到了FnPredicate類型,那么它實現哪些特征

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

這里是! 您已經傳遞了帶有&String的閉包,因此此定義中的T推斷為String ,即實現的特征是Predicate<String>

現在,如果您回想起第一部分,您會發現實現中沒有Predicate<String>

如何解決呢?

就目前而言,我看到兩種可能性:

  1. 您可以使用第二種實現,並使您的謂詞引用字節切片&[u8] 我無法使用庫本身對其進行測試,因為它不在操場上,但是如果我只是在關閉時進行了更改,我會立即收到錯誤消息
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]`

幸運的是,通過將字符串文字更改為字節字符串( parker ),可以很容易地解決此問題:

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

請注意,我還利用了Clippy提示來簡化相關代碼(在操場上,它位於右側的“工具”按鈕下)。

現在,如果您將此閉包傳遞給predicate::function ,那么一切都可以正常工作。

  1. 另一種方法是使用第一個實現-您可以看到Predicate<str> (即,函數謂詞接收&str )也受支持,盡管有點復雜。 但是現在看來這似乎不是問題,因為無論如何都實現了特征-這只是間接的一個內部層,但這不是您的問題( assert_cmd板條箱應該自己處理)。 這段代碼尤其可以很好地編譯:
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 ,並且這不是限制。 當然,庫作者也知道這一點,通常會迫使您采用最通用的方式,即您必須使用最少的間接方式進行工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM