8章6〜8節まで。
トレイトの利用例。
標準ライブラリのから、ちょっとしたテクニック紹介など。
読むだけスタイルで進めた。
全体的に、こんなことできるんだなぁというのを知れたのは良かった。
しかし、ようやく基礎編が終わったなー。
長かった。
おぼえがき
標準ライブラリのトレイト
std::ops::Eq
は、std::opts::PartialEq
を継承しているだけっぽいstd::opts::Eq
は、a==b,b==c,a==c,a==a
を保証するstd::opts::PartialEq
は、a==a
は保証しない(NaN==Nanなどはfalseになる)- ハッシュマップのキーのように、
a==a
が成り立たないとこまる場面ではEqが要求される- この違いはコンパイラじゃ検出できない気がする。実装側がこのルールに従わないと世界が崩壊するのかな
−
std::marker::Sized
という特殊なトレイトがある
- この違いはコンパイラじゃ検出できない気がする。実装側がこのルールに従わないと世界が崩壊するのかな
−
- コンパイル時に型のサイズが決定できることを表す
- 定義は空っぽい
pub trait Sized { }
- ユーザは実装することができない
- コンパイラが自動で付与する
- Sizedを実装していないと、値の受け渡しができない
- Sizedを実装していない型は、
str
や[T]
など - Sizedを実装していない型の参照も特別で、サイズ情報が付与されるため、データサイズが大きくなる
- Sizedのようなトレイトはopt-in build-in traits(OIBITs)と呼ばれるとのこと
- Syncも仲間とのこと
演算子のオーバーロード
− Rustは既存の演算子(+や-など)に対してならオーバーロードできる
- あくまで既存の演算子だけ。自分で新たに作成することはできない
- 各演算子のトレイトを実装することで、オーバーロードする。以下、+のトレイトの例
pub trait Add<RHS = Self> { type Output; fn add(self, rhs: RHS) -> Self::Output }
- 他にも
std::opts
に色々あるっぽい! : Not
否定* : Deref
参照外し[]: Index
配列やハッシュマップのインデクシング- Vecのインデクシングは下記ジェネリクスを実装している
Index<usize>
...vec[0]
Index<RangeFrom<usize>>
...vec[1..]
Index<RangeFull>
...vec[..]
- Vecのインデクシングは下記ジェネリクスを実装している
トレイトのテクニック
- StringとInto
- Intoを使ったオプショナル引数
- 引数の型を
arg1: tmpl Into<Option<usize>>, arg2: Into<Option<usize>>
としたとする - 呼び出し側は、
func(1, None);
のように呼び出せる(Some(None))も要らない
- 引数の型を
- 以下などはパスネームとして振る舞う(AsRef
を実装) - Path, PathBuf, &str, String, OsStr, OsString
- 引数の型を
path: impleAsRef<Path>
として定義すると良いpath.as_ref()
などのメソッドが使えるFile::new(path.as_ref())?;
- &strとstr
- トレイトのメソッドの多くは、
&self
や&mut self
を取るらしい - そこで、
impl SomeTrait for str { fn func(&self); }
と実装する - そうすれば、
let s="str"; s.func();
と、参照外しも要らずに自然に呼び出せる - という話。
- Box
などでも使える let bs = Box::new(*s); bs.func();
- トレイトのメソッドの多くは、
- 外部クレートの型に、外部クレートのトレイトは実装できない
- しかし、タプル構造体で囲んだ型を定義すればできる
struct ExlibStructWrapper(ExLibStruct);
みたいな感じimpl ExLibTrait for ExLibStructWrappter{ }
で実装let e = ExLibStructWrappter(ExLibStruct::new());
として使う −e.method();
という感じで、ExLibTraitのメソッドを使えるようになる
- 列挙型を使った型の混合。便利かも
- 以下書籍のサンプルコード抜粋(コメントは省略)
#[derive(Debug)] enum Either<A, B> { A(A), B(B), } impl<A, B> fmt::Display for Either<A, B> where A: fmt::Display, B: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Either::A(a) => a.fmt(f), Either::B(b) => b.fmt(f), } } } let mut v: Vec<Either<bool, i32>> = vec![]; v.push(Either::A(true)); v.push(Either::B(1i32)); for e in v { println!("{}", e); }
課題
- 実践で使えるにはまだまだ先 − 構文に慣れたら一度見直しましょー
- 作者: κeen,河野達也,小松礼人
- 出版社/メーカー: 技術評論社
- 発売日: 2019/05/08
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る