📝
ト。─トレイトについて─
タイトル負けです。
トレイト
トレイトの作成
デフォルト実装とは、トレイト内で具体的な中身があるメソッドを指す。オーバーライドがわかればしっくりきます。
// メソッドなし
trait Exp { // 頭文字は大文字。
fn animals(&self) -> String;
}
// メソッドあり
trait Exp {
fn animals(&self) -> String;
fn foods(&self) -> String {
let x = &self.animals();
format!("{}", x)
}
}
トレイトの利用
デフォルト実装を持たないメソッドは必須メソッドと呼ばれる。
必須メソッドはトレイト契約をする上で必ず使用しないといけない。
struct Zoo {
kind: String,
animal_age: i32,
}
trait Exp {
fn animals(&self) -> String; // 必須メソッド
fn foods(&self) -> String { // デフォルト実装
let x = &self.animals();
format!("{}", x)
}
}
impl Exp for Zoo { // トレイト名を先に、型の名前を後に。
fn animals(&self) -> String { // 中身がしょうもなくても必要
self.kind
}
オーバーライド
デフォルト実装の中身を上書きして利用する。
トレイトで決めたテンプレートのメソッド(デフォルト実装)を違う動きにするということ。
struct Zoo {
kind: String,
age: i32,
}
trait Exp {
fn animals(&self) -> i32; // 必須メソッド
fn foods(&self) -> String { // デフォルト実装
let z = &self.animals();
format!("{}", z)
}
}
impl Exp for Zoo {
fn animals(&self) -> i32 {
self.age
}
fn foods(&self) -> String { // 返り値の型を同じにする
let zoo_age = &self.animals();
let two_age = zoo_age * 2;
format!("this animal is {}", two_age)
}
}
fn main(){
let x = Zoo {
kind: "tiger".to_string(),
age: 20,
};
println!("{}", x.foods());
}
トレイト境界
トレイト境界とは、ジェネリック型パラメータが特定のトレイトを実装していることを要求する制約。
これにより、ジェネリックな関数や構造体が、特定の振る舞い(トレイトが定義するメソッドや特性)を持つ型でのみ動作するように保証できる。
構文
a.ジェネリック型パラメータの後にトレイト名をつける。
このコードでは、Tがstd::fmt::Displayトレイトを実装している方でなけらばならないと指定している。Displayを実装した型でのみ呼び出せる。
fn print<T: std::fmt::Display>(value: T) {
println!("{}", value);
}
b.where句の利用
複数のパラメータに異なるトレイト境界を指定できる。
fn cost<T, E>(arg1: T, arg2: E) -> i32 // {}はいらない。
where
T: Zoo,
E: Zoo,
{
arg1.animals() + arg2.animals()
}
- トレイト境界を使わない書き方
この書き方の場合、複数の型を扱えない。
fn cost(arg: impl Zoo) -> i32 { // 仮引数: impl トレイト名
let drink_cost = arg.animals();
drink_cost
}
標準ライブラリにあるトレイト達(随時更新)
勉強したものから追加していきますヨ。
Defaultトレイト
std::default::Default
このトレイトを実装する型はdefault()メソッドを通じて、「標準的な初期値」を返すことができます。
i32やStringなどの標準ライブラリの型には、子のトレイトが実装されており、default()を呼び出すと0やからの文字列を作ってくれる。
trait Default for 型名 {
fn default() -> Self {
}
}
AsRefトレイト
色々な型に変換してくれる。
?Sizedはサイズが不定な型でもいいよってこと。
pub trait AsRef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
// &str に変換
let s = String::from("hello.txt");
let str_ref: &str = s.as_ref();
Discussion