मेरे पास एक AdoptablePet विशेषता है जो आपको fn do_adoption(id: &Self::Id) -> BoxFuture<'static, Result<Self, Self::Error>>; के माध्यम से एक पालतू जानवर को अतुल्यकालिक रूप से अपनाने की अनुमति देती है।

मेरे पास एक Dog विशेषता है जो अपनाने योग्य है (pub trait Dog: AdoptablePet) और आपको वास्तव में पालतू जानवर को अपनाने की अनुमति देने से पहले एक संबद्ध AdoptingPerson और एक adoption_policy लेता है। adoption_policy केवल एक फ़ंक्शन है जो Results लौटाने वाले बॉक्सिंग फ़्यूचर्स की एक सरणी देता है।

जब मैं एक Pitbull बनाने के लिए जाता हूं, जो Dog और AdoptablePet दोनों को लागू करता है, तो सब कुछ काम करता है, लेकिन जैसे ही मैं adoption_policy का डिफ़ॉल्ट कार्यान्वयन करने का प्रयास करता हूं (जैसा कि यह सभी Pitbulls के लिए समान होगा) मुझे बॉक्सिंग फ्यूचर्स के सभी जॉइनिंग के बीच सही संदर्भ नहीं मिल रहे हैं।

जब मैं join_all adoption_policy Vec की कोशिश करता हूं, तो इसमें बॉक्सिंग फ्यूचर्स के बजाय बॉक्सिंग फ्यूचर्स के संदर्भ होते हैं। जब मैं उन्हें मैप और डीरेफरेंस करने का प्रयास करता हूं, तो मुझे उधार चेकर त्रुटि मिलती है (कोड में [EXAMPLE B] देखें):

error[E0277]: the trait bound `&std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<(), AdoptionError>> + std::marker::Send>>: core::future::future::Future` is not satisfied
  --> src/lib.rs:70:13
   |
70 |             join_all(Self::adoption_policy(adopter, id).iter()).then(|policy_results| {
   |             ^^^^^^^^ the trait `core::future::future::Future` is not implemented for `&std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<(), AdoptionError>> + std::marker::Send>>`
   |
   = help: the following implementations were found:
             <std::pin::Pin<P> as core::future::future::Future>
   = note: required by `futures_util::future::join_all::join_all`

error[E0599]: no method named `then` found for type `futures_util::future::join_all::JoinAll<&std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<(), AdoptionError>> + std::marker::Send>>>` in the current scope
  --> src/lib.rs:70:65
   |
70 |             join_all(Self::adoption_policy(adopter, id).iter()).then(|policy_results| {
   |                                                                 ^^^^

error[E0277]: the trait bound `&std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<(), AdoptionError>> + std::marker::Send>>: core::future::future::Future` is not satisfied
  --> src/lib.rs:70:13
   |
70 |             join_all(Self::adoption_policy(adopter, id).iter()).then(|policy_results| {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `core::future::future::Future` is not implemented for `&std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<(), AdoptionError>> + std::marker::Send>>`
   |
   = help: the following implementations were found:
             <std::pin::Pin<P> as core::future::future::Future>
   = note: required by `futures_util::future::join_all::JoinAll`

मैं थोड़ा खो गया हूँ। अगर मैं adopt में join_all नहीं करता (और केवल Self::do_adoption(id) लौटाता हूं तो सब कुछ काम करता है (कोड में [EXAMPLE A] देखें)। क्या हो रहा है?

कोड (गिट रेपो में उपलब्ध):

#![feature(async_await)]
use futures::future::{self, join_all, BoxFuture};

#[derive(Debug)]
pub struct AdoptionError;

pub trait AdoptablePet
where
    Self: Sized,
{
    /// The id of the pet to adopt.
    type Id;

    /// Adopt the pet.
    fn do_adoption(id: &Self::Id) -> BoxFuture<'static, Result<Self, AdoptionError>>;
}

pub trait Dog: AdoptablePet
where
    // XXX: Are these all needed?
    Self: Sized + Send,
    <Self as AdoptablePet>::Id: Sync,
    Self: 'static,
    Self::AdoptingPerson: Sync,
{
    /// The Person adopting a dog.
    type AdoptingPerson;

    /// The policy to check when a person is adopting a particular dog.
    fn adoption_policy(
        adopter: &Self::AdoptingPerson,
        id: &Self::Id,
    ) -> Vec<BoxFuture<'static, Result<(), AdoptionError>>>;

    /// Policy-aware adoption.
    fn adopt(
        adopter: &Self::AdoptingPerson,
        id: &Self::Id,
    ) -> BoxFuture<'static, Result<Self, AdoptionError>> {
        // [EXAMPLE A]
        // Doing the following works...
        /*
        if true {
            Self::do_adoption(id)
        } else {
            Box::pin(future::ready(Err(AdoptionError{})))
        }
        */

        /* [EXAMPLE B]
           But this is what I want to do. This is the error:

            --> src/lib.rs:71:13
             |
          71 | /             join_all(
          72 | |
          73 | |
          74 | |                 --> src/lib.rs:65:13
          ...  |
          86 | |                 Self::adoption_policy(adopter, id).iter(),
          87 | |             )
             | |_____________^ the trait `core::future::future::Future` is not implemented for `&std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = std::result::Result<(), AdoptionError>> + std::marker::Send>>`
             |
             = help: the following implementations were found:
                       <std::pin::Pin<P> as core::future::future::Future>
             = note: required by `futures_util::future::join_all::JoinAll`
        */
        Box::pin(
            // Check all the adoption rules in the policy.
            join_all(Self::adoption_policy(adopter, id).iter()).then(|policy_results| {
                // Depending on the result, do the (async/long-running)
                // adoption or return an error.
                let has_policy_failure = policy_results.any(|x| x.is_err());
                if !has_policy_failure {
                    Self::do_adoption(id)
                } else {
                    Box::pin(future::ready(Err(AdoptionError {})))
                }
            }),
        )
    }
}

/// Implementation.

#[derive(Debug, Clone, PartialEq)]
pub struct DogId(pub String);

pub struct Pitbull {
    pub id: DogId,
}

impl AdoptablePet for Pitbull {
    type Id = DogId;

    fn do_adoption(id: &Self::Id) -> BoxFuture<'static, Result<Self, AdoptionError>> {
        Box::pin(future::ready(Ok(Pitbull { id: id.clone() })))
    }
}

impl Dog for Pitbull {
    type AdoptingPerson = Person;
    fn adoption_policy(
        _adopter: &Self::AdoptingPerson,
        _id: &Self::Id,
    ) -> Vec<BoxFuture<'static, Result<(), AdoptionError>>> {
        vec![
            // 1. Check if they have had their shots.
            // 2. Check if the adopter has children and if the breed is good with children.
            // etc.
        ]
    }
}

pub struct Person {
    name: String,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        futures::executor::block_on(async {
            let id = DogId("fluffy123".to_string());
            let adopter = Person {
                name: "Fred".to_string(),
            };
            let _ = Pitbull::adopt(&adopter, &id).await.unwrap();
        });
    }
}

मैं फ्यूचर्स-पूर्वावलोकन संस्करण 0.3.0-अल्फा.16 का उपयोग कर रहा हूं।

0
Chris 18 जून 2019, 17:08

1 उत्तर

सबसे बढ़िया उत्तर

यहाँ कार्यशील संस्करण है:

fn adopt(
    adopter: &Self::AdoptingPerson,
    id: &'static Self::Id,
) -> BoxFuture<'static, Result<Self, AdoptionError>> {
    Box::pin(
        join_all(Self::adoption_policy(adopter, id)).then(move |policy_results| {
            let has_policy_failure = policy_results.iter().any(|x| x.is_err());
            if !has_policy_failure {
                Self::do_adoption(id)
            } else {
                Box::pin(future::ready(Err(AdoptionError {})))
            }
        }),
    )
}

परिवर्तन:

  1. join_all को फ्यूचर्स का स्वामित्व लेने की जरूरत है, उनके संदर्भ में नहीं: join_all(Self::adoption_policy(adopter, id))
  2. FutureExt::then तक पहुंच प्राप्त करने के लिए futures::future::FutureExt को आयात किया जाना चाहिए।
  3. any Iterator पर एक विधि है, Vec नहीं: policy_results.iter().any(/* ... */)
  4. आपकी सीमा के कारण id को 'static होना चाहिए: id: &'static Self::Id
  5. उधार को रोकने के लिए id को क्लोजर में ले जाने की आवश्यकता है: move |policy_results| { /* ... */ }

यह सभी देखें:

2
Shepmaster 19 जून 2019, 18:58