I have this code (playground):
use std::sync::Arc;
pub trait Messenger : Sync + Send {
fn send_embed String>(&self, u6
Traits and Traits
In Rust, you can use trait to define an interface comprised of:
and you can use traits either:
However... only some traits can be used directly as types. Those traits that do are labeled Object Safe.
It is now considered unfortunate that a single trait keyword exists to define both full-featured and object-safe traits.
Interlude: How does run-time dispatch work?
When using a trait as a type: &Trait, Box, Rc, ... the run-time implementation uses a fat pointer composed of:
Method calls are dispatched through the virtual pointer to a virtual table.
For a trait like:
trait A {
fn one(&self) -> usize;
fn two(&self, other: usize) -> usize;
}
implemented for type X, the virtual table will look like (.
The run-time dispatch is thus performed by:
This means that looks like:
fn x_as_a_two(this: *const (), other: usize) -> usize {
let x = unsafe { this as *const X as &X };
x.two(other)
}
Why cannot I use any trait as a type? What's Object Safe?
It's a technical limitation.
There are a number of traits capabilities that cannot be implemented for run-time dispatches:
Self in the signature.There are two ways to signal this issue:
trait as a type if it has any of the above,trait as a type.For now, Rust chooses to signal the issue early on: traits that do not use any of the above features are call Object Safe and can be used as types.
Traits that are not Object Safe cannot be used as types, and an error is immediately triggered.
Now what?
In your case, simply switch from compile-time polymorphism to run-time polymorphism for the method:
pub trait Messenger : Sync + Send {
fn send_embed(&self, u64, &str, f: &FnOnce(String) -> String)
-> Option;
}
There is a little wrinkle: FnOnce requires moving out of the f and it's only borrowed here, so instead you need to use FnMut or Fn. FnMut is next more generic method, so:
pub trait Messenger : Sync + Send {
fn send_embed(&self, u64, &str, f: &FnMut(String) -> String)
-> Option;
}
This makes the Messenger trait Object Safe and therefore allows you to use a &Messenger, Box, ...