"items from traits can only be used if the trait is implemented and in scope"

In short I'm wondering if it's possible to use a trait object in a struct, but not have an implemented version of it ready to plug in yet. I'm sure I might be doing something dumb.

The simplified version of my code:

pub trait ValidatePayment {
    fn get_invoice(&self) -> Bolt11Invoice;
    fn validate(&self) -> bool;
}

pub struct InternalAPI {
    validator: Option<Arc<Mutex<Box<dyn ValidatePayment + Send>>>>,
}

async fn pay(
        &self,
    ) -> Result<Response<common_msgs::PayResponse>, Status> {
        let invoice = if let Some(validator) = self.validator {
            *validator.get_invoice()
        } else {
            return Err(Status::new(
                Code::Unimplemented,
                "Paying for service is unsupported",
            ))
        };
		
		// ETC

Here is the error I get:

error[E0599]: no method named `get_invoice` found for struct `Arc<Mutex<Box<(dyn ValidatePayment + Send + 'static)>>>` in the current scope
   --> teos/src/api/internal.rs:117:24
    |
117 |             *validator.get_invoice()
    |                        ^^^^^^^^^^^ method not found in `Arc<Mutex<Box<(dyn ValidatePayment + Send + 'static)>>>`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
note: `ValidatePayment` defines an item `get_invoice`, perhaps you need to implement it
   --> teos/src/fees.rs:9:1
    |
9   | pub trait ValidatePayment {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^

The error indicates that the trait needs to be implemented. But I'm wondering if there's a way I can specify the trait but not implement for right now... RN I just want to pass in a None value in the actual code, but write a dummy implementation for the tests.

Tried to simplify the code as much as possible here, but lmk if there's anything else I need to add here that would be useful...

Thanks in advance :]

No. The error message tells you that you can only call a trait method on a type if:

  • that type implements the trait (which a trait object does), and
  • the trait is in scope.

You could as well use a trait-bounded generic type parameter. It is not necessary for a concrete type implementing the trait to actually exist; that would be bad. (You couldn't then create libraries that only define but not implement traits, for example.)

The root cause of your problem here is that you can't just call methods on the wrapped value of a Mutex, you have to lock the mutex to access the inner value, that's the whole point of the mutex.


By the way, Arc<Mutex<Box<dyn Trait>>> is unnecessary. Replace it with Arc<Mutex<dyn Trait>>.

2 Likes

Ohh I had a feeling I was missing something basic - lock did the trick. I'll have to keep learning about the other things you mentioned. Thanks!