Rust - Trait
A trait tells the Rust compiler about functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way.
So trait
is similar to a feature often called interfaces in other languages, although with some differences.
On the other hand:
We can use trait bounds to specify that a generic can be any type that has certain behavior.
We are not going to tell every detail of trait
, you can read following sections in Rust Book for them:
- 10-2 “Traits: Defining Shared Behavior”
- 17-2 “Using Trait Objects That Allow for Values of Different Types”
- 19-3 “Advanced Trait”
Instead, I’m trying to pick and illustrate some concepts that are hard to understand at the beginning, with some examples.
Trait With Associated Type VS Trait With Generic Type
trait
with associated type:
trait IFoo {
type Ret;
fn foo(&self) -> Self::Ret;
}
This defines only ONE trait
, the implementor has to specify the exact type of Ret
during impl
. Each implementor can only implement this trait
for once.
E.g.
struct Foo1 {}
impl IFoo for Foo2 {
type Ret = i32;
fn foo(&self) -> Self::Ret {
1
}
}
struct Foo2 {}
impl IFoo for Foo2 {
type Ret = string;
fn foo(&self) -> Self::Ret {
"a"
}
}
trait
with generic type:
trait IFoo<T> {
fn foo(&self) -> T;
}
Since the trait
is takes generic type, it means there could be more than one “concrete” traits that a type could implement.
E.g.
struct Foo {}
impl IFoo<i32> for Foo {
fn foo(&self) -> i32 {
1
}
}
impl IFoo<string> for Foo {
fn foo(&self) -> string {
"a"
}
}
Foo
can implement both IFoo<i32>
trait
and IFoo<string>
trait
. When using the instance of Foo
, if we simply invoke foo
, then compiler can not infer to a unique type and will raise an error. To fix that, we have to explicitly annotate the type:
fn main() {
let foo = Foo {};
let _: string = foo.foo();
//let _ = foo.foo(); // Build Error
}
NOTE they can exist at the same time
Comments