Open6
Rustメモ
拡張メソッド
ライブラリ等で提供されているTraitのソースを変更すること無くメソッドを追加する。
C#の拡張メソッドっぽいやつ。
参考になるCrate
例えばReadに下記のようなメソッドを生やす。
use std::io::Cursor;
use byteorder::ReadBytesExt;
let mut rdr = Cursor::new(vec![2, 5]);
assert_eq!(2, rdr.read_u8().unwrap());
assert_eq!(5, rdr.read_u8().unwrap());
実装
pub trait ReadBytesExt: io::Read {
fn read_u8(&mut self) -> Result<u8> {
let mut buf = [0; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
}
}
impl<R: io::Read + ?Sized> ReadBytesExt for R {}
全文はこちら
- io::ReadのSub Traitとして定義することでio::Readのメソッドに依存できる
- Traitにデフォルト実装をしている
- R: io::Read に implすることでメソッドを付け足す
- Traitに対してのimplなのでTrait境界の書き方になる
しかしデフォルト実装に頼りまくるのはなんとなくtraitのコンセプトに反しているような気持ち悪さを感じる。付け足す拡張メソッド数が増えると楽するためにデフォルト実装使いたくなる気持ちはわかる。
驚異 impl Read for &[u8];
let test_bytes = vec![0xA1_u8, 0x86, 0x15];
//let mut reader = Cursor::new(test_bytes); <-- Cursor使わなくてもいい
let mut reader = &test_bytes[..]; //<-- これでスライス化するだけ
reader.read_exact(buff);
関数引数をmutにする件
Option::mapのラムダがResultを返す場合
Result<Option<i32>> で返したい。
#[test]
fn test() {
use anyhow::*;
let v = Some("123");
let x = match v {
Some(str) => str
.parse::<i32>()
.context("failed to convert to i32")
.map(Some),
None => Ok(None),
};
assert_eq!(x.unwrap(), Some(123));
}
長いのでこう書ける。
#[test]
fn test2() {
use anyhow::*;
let v = Some("123");
let x = v
.map(|str| str.parse::<i32>().context("failed to convert to i32"))
.transpose();
assert_eq!(x.unwrap(), Some(123));
}