<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://johnwick.cc/index.php?action=history&amp;feed=atom&amp;title=Rust%3A_Trait_With_Async_Methods</id>
	<title>Rust: Trait With Async Methods - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://johnwick.cc/index.php?action=history&amp;feed=atom&amp;title=Rust%3A_Trait_With_Async_Methods"/>
	<link rel="alternate" type="text/html" href="https://johnwick.cc/index.php?title=Rust:_Trait_With_Async_Methods&amp;action=history"/>
	<updated>2026-05-07T04:51:48Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.1</generator>
	<entry>
		<id>https://johnwick.cc/index.php?title=Rust:_Trait_With_Async_Methods&amp;diff=633&amp;oldid=prev</id>
		<title>PC: Created page with &quot;First of all, I hope that you are familiar with Rust Trait, a type we use to define shared behavior in an abstract way. For me, I see it as an inferior version the Swift Protocol (I am sorry if you don’t agree, but the second we cannot add required properties/fields in trait, it is over)! Anyway! Use async methods with Traits can be inevitable sometimes, but depending on the use case, this can require a bit of trial and error to actually get it to work! In this ar...&quot;</title>
		<link rel="alternate" type="text/html" href="https://johnwick.cc/index.php?title=Rust:_Trait_With_Async_Methods&amp;diff=633&amp;oldid=prev"/>
		<updated>2025-11-21T00:25:14Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;First of all, I hope that you are familiar with Rust Trait, a type we use to define shared behavior in an abstract way. For me, I see it as an inferior version the Swift Protocol (I am sorry if you don’t agree, but the second we cannot add required properties/fields in trait, it is over)! Anyway! Use async methods with Traits can be inevitable sometimes, but depending on the use case, this can require a bit of trial and error to actually get it to work! In this ar...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;First of all, I hope that you are familiar with Rust Trait, a type we use to define shared behavior in an abstract way.&lt;br /&gt;
For me, I see it as an inferior version the Swift Protocol (I am sorry if you don’t agree, but the second we cannot add required properties/fields in trait, it is over)!&lt;br /&gt;
Anyway!&lt;br /&gt;
Use async methods with Traits can be inevitable sometimes, but depending on the use case, this can require a bit of trial and error to actually get it to work!&lt;br /&gt;
In this article, let me share with you really quick on how we can create a trait with async methods, couple problems we might encounter and some workarounds!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Basic&lt;br /&gt;
First of all, defining async functions in a trait does not cause any problems it self!&lt;br /&gt;
trait Animal {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Dog;&lt;br /&gt;
&lt;br /&gt;
impl Animal for Dog {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        println!(&amp;quot;eating {}!&amp;quot;, food);&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
First Problem&lt;br /&gt;
When do those problems come in?&lt;br /&gt;
Dynamic Dispatch!&lt;br /&gt;
PS: If you want to read more about Dynamic Dispatch and Generics, please check out one of my previous articles Rust: Dyn (Dynamic Dispatch) vs Generics (Monomorphism / Static Dispatch)!&lt;br /&gt;
For example, let’s add a Zoo that contains a field of a vector of Animals!&lt;br /&gt;
struct Zoo {&lt;br /&gt;
    pub animals: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
And unfortunately, here is what we get. When the trait contains async method, it is not dyn compatible anymore!&lt;br /&gt;
&lt;br /&gt;
[[file:Async_1.jpg|700px]]&lt;br /&gt;
&lt;br /&gt;
With Async Trait&lt;br /&gt;
To solve our problem above, we can use this async-trait crate, a crate that provides an attribute macro to make async functions in traits work with dyn traits.&lt;br /&gt;
All we have to do is to mark our trait and the implementation with async_trait.&lt;br /&gt;
&lt;br /&gt;
struct Zoo {&lt;br /&gt;
    pub animals: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#[async_trait]&lt;br /&gt;
trait Animal {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Dog;&lt;br /&gt;
&lt;br /&gt;
#[async_trait]&lt;br /&gt;
impl Animal for Dog {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        println!(&amp;quot;eating {}!&amp;quot;, food);&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
Perfect!&lt;br /&gt;
Let’s add a dummy implementation to the zoo just to confirm.&lt;br /&gt;
impl Zoo {&lt;br /&gt;
    async fn feed_animals(&amp;amp;self) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        for animal in self.animals.iter() {&lt;br /&gt;
            animal.eat(&amp;quot;food&amp;quot;).await?&lt;br /&gt;
        }&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#[tokio::main]&lt;br /&gt;
async fn main() -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
    let zoo = Zoo {&lt;br /&gt;
        animals: vec![Box::new(Dog)],&lt;br /&gt;
    };&lt;br /&gt;
    zoo.feed_animals().await?;&lt;br /&gt;
    Ok(())&lt;br /&gt;
}&lt;br /&gt;
Another Problem&lt;br /&gt;
However, what if we have a field within the Dog that holds an array of Animal?&lt;br /&gt;
struct Dog {&lt;br /&gt;
    pub friends: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
[[file:Async_2.jpg|700px]]&lt;br /&gt;
&lt;br /&gt;
Oops!&lt;br /&gt;
There are couple ways of solving this!&lt;br /&gt;
Approach 1: Box Future&lt;br /&gt;
First of all, let’s agree on this, async function produce Future. If we can write our function as async, we can convert it to a regular sync fn that returns a Future instead!&lt;br /&gt;
So!&lt;br /&gt;
The solution should be pretty straightforward now!&lt;br /&gt;
Make our function sync and return this BoxFuture from the futures crate!&lt;br /&gt;
This is actually what async-trait crate does underwood, inserting a BoxFuture and doing the boxing for us.&lt;br /&gt;
Let’s remove those async_trait attributes and change our trait method as well as the implementation to the following.&lt;br /&gt;
use futures::future::{ready, BoxFuture};&lt;br /&gt;
trait Animal {&lt;br /&gt;
    fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; BoxFuture&amp;lt;&amp;#039;static, anyhow::Result&amp;lt;()&amp;gt;&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
Here, I am using the &amp;#039;static as my lifetime, but you can also use other lifetimes based on your needs.&lt;br /&gt;
We can then implement the trait like following.&lt;br /&gt;
impl Animal for Dog {&lt;br /&gt;
    fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; BoxFuture&amp;lt;&amp;#039;static, anyhow::Result&amp;lt;()&amp;gt;&amp;gt; {&lt;br /&gt;
        println!(&amp;quot;eating {}!&amp;quot;, food);&lt;br /&gt;
        Box::pin(ok(())) // equivalent to Box::pin(ready(Ok(())))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
Or if we want to use self and call some other async functions. No problem!&lt;br /&gt;
impl Animal for Dog {&lt;br /&gt;
    fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; BoxFuture&amp;lt;&amp;#039;static, anyhow::Result&amp;lt;()&amp;gt;&amp;gt; {&lt;br /&gt;
        if let Some(friend) = self.friends.first() {&lt;br /&gt;
            return friend.eat(food);&lt;br /&gt;
        }&lt;br /&gt;
        println!(&amp;quot;eating {}!&amp;quot;, food);&lt;br /&gt;
        Box::pin(ok(())) // equivalent to Box::pin(ready(Ok(())))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
In our Zoo, we actually don’t have to change anything and just await on that eat exactly the same as above!&lt;br /&gt;
impl Zoo {&lt;br /&gt;
    async fn feed_animals(&amp;amp;self) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        for animal in self.animals.iter() {&lt;br /&gt;
            animal.eat(&amp;quot;food&amp;quot;).await?&lt;br /&gt;
        }&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
Approach 2: Implement Sync&lt;br /&gt;
The compiler’s message already gave this out, but actually, all we have to do is to implement Sync for our Animal trait!&lt;br /&gt;
#[async_trait]&lt;br /&gt;
trait Animal: Sync {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
Yes!&lt;br /&gt;
That’s it!&lt;br /&gt;
By the way, this is also what we need to do if we want to spawn the eat function to some other thread, or we want to join_all for concurrent execution!&lt;br /&gt;
If you want to find out more about those, please feel free to check out couple of my previous articles!&lt;br /&gt;
* 		Rust: Execute Multiple Async Simultaneously: Multithreading vs Futures&lt;br /&gt;
* 		Rust: Transfer Data Between Threads&lt;br /&gt;
Code Snippet&lt;br /&gt;
That’s it for the day!&lt;br /&gt;
Here are the full snippets for you to give it a try yourself!&lt;br /&gt;
Async Trait Version&lt;br /&gt;
use async_trait::async_trait;&lt;br /&gt;
&lt;br /&gt;
#[tokio::main]&lt;br /&gt;
async fn main() -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
    let zoo = Zoo {&lt;br /&gt;
        animals: vec![Box::new(Dog { friends: vec![] })],&lt;br /&gt;
    };&lt;br /&gt;
    zoo.feed_animals().await?;&lt;br /&gt;
    Ok(())&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Zoo {&lt;br /&gt;
    pub animals: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl Zoo {&lt;br /&gt;
    async fn feed_animals(&amp;amp;self) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        for animal in self.animals.iter() {&lt;br /&gt;
            animal.eat(&amp;quot;food&amp;quot;).await?&lt;br /&gt;
        }&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#[async_trait]&lt;br /&gt;
trait Animal: Sync {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Dog {&lt;br /&gt;
    pub friends: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#[async_trait]&lt;br /&gt;
impl Animal for Dog {&lt;br /&gt;
    async fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        println!(&amp;quot;eating {}!&amp;quot;, food);&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
BoxFuture Version&lt;br /&gt;
use futures::future::{ready, BoxFuture};&lt;br /&gt;
&lt;br /&gt;
#[tokio::main]&lt;br /&gt;
async fn main() -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
    let zoo = Zoo {&lt;br /&gt;
        animals: vec![Box::new(Dog { friends: vec![] })],&lt;br /&gt;
    };&lt;br /&gt;
    zoo.feed_animals().await?;&lt;br /&gt;
    Ok(())&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Zoo {&lt;br /&gt;
    pub animals: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl Zoo {&lt;br /&gt;
    async fn feed_animals(&amp;amp;self) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;br /&gt;
        for animal in self.animals.iter() {&lt;br /&gt;
            animal.eat(&amp;quot;food&amp;quot;).await?&lt;br /&gt;
        }&lt;br /&gt;
        Ok(())&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
trait Animal {&lt;br /&gt;
    fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; BoxFuture&amp;lt;&amp;#039;static, anyhow::Result&amp;lt;()&amp;gt;&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Dog {&lt;br /&gt;
    pub friends: Vec&amp;lt;Box&amp;lt;dyn Animal&amp;gt;&amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
impl Animal for Dog {&lt;br /&gt;
    fn eat(&amp;amp;self, food: &amp;amp;str) -&amp;gt; BoxFuture&amp;lt;&amp;#039;static, anyhow::Result&amp;lt;()&amp;gt;&amp;gt; {&lt;br /&gt;
        if let Some(friend) = self.friends.first() {&lt;br /&gt;
            return friend.eat(food);&lt;br /&gt;
        }&lt;br /&gt;
        println!(&amp;quot;eating {}!&amp;quot;, food);&lt;br /&gt;
        Box::pin(ok(())) // equivalent to Box::pin(ready(Ok(())))&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Thank you for reading!&lt;br /&gt;
That’s it for this article!&lt;br /&gt;
Happy trait-ing!&lt;br /&gt;
&lt;br /&gt;
Read the full article here: https://blog.stackademic.com/rust-trait-with-async-methods-a62ce5ad5be8&lt;/div&gt;</summary>
		<author><name>PC</name></author>
	</entry>
</feed>