やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Rustの高度な機能(型)

 型エイリアス、never型、Sizedトレイト。

成果物

参考

エイリアス

type Kilometers = i32;
$ rustc main.rs
$ ./main
x + y = 10

 Box<Fn() + Send + 'static>のような長い型がある。これを多くの場面で使うのは面倒。

fn main() {
    let f: Box<Fn() + Send + 'static> = Box::new(|| println!("hi"));
}
fn takes_long_type(f: Box<Fn() + Send + 'static>) {
    // --snip--
}
fn returns_long_type() -> Box<Fn() + Send + 'static> {
    // --snip--
}

 これをエイリアスで置き換えると以下。すっきり。

type Thunk = Box<Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("hi"));
fn takes_long_type(f: Thunk) {
    // --snip--
}
fn returns_long_type() -> Thunk {
    // --snip--
}

 以下はResult<T,E>が多用される例。

use std::io::Error;
use std::fmt;
pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
    fn flush(&mut self) -> Result<(), Error>;
    fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>;
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Error>;
}

 以下のように別名定義してしまう。

type Result<T> = Result<T, std::io::Error>;
pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize>;
    fn flush(&mut self) -> Result<()>;

    fn write_all(&mut self, buf: &[u8]) -> Result<()>;
    fn write_fmt(&mut self, fmt: Arguments) -> Result<()>;
}

 型を新しくすると略記できる。

never型

fn bar() -> ! {
    // --snip--
}

 !型。never typeと呼ぶ。関数が返らないときに使う。

 panic!()の戻り値の型は!である。match式では全アームで同じ型を返さねばならない。なのに以下の_i32を返していないのにコンパイル成功する。!はこういうときに使う。continue!である。

match 1 {
    1 => 5,
    _ => panic!(),
}
match x {
    Ok(num) => num,
    Err(_)_ => continue,
}

 Option型のunwrap関数の戻り値はジェネリック型。!型もTの中に含まれる。

impl<T> Option<T> {
    pub fn unwrap(self) -> T {
        match self {
            Some(val) => val,
            None => panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}

動的サイズ付け型とSizedトレイト

動的サイズ付け型

 DSTと略される。実行時にしかサイズを知れない値のコードを書ける。RustではSizedトレイトによりDSTを扱う。

 Sizedトレイトは自動的に適用される。実行時にサイズがわかるものが対象。

fn generic<T>(t: T) {
    // --snip--
}
fn generic<T: Sized>(t: T) {
    // --snip--
}

 以下のように?を先頭に付与すると「TSizedかもしれないし、違うかも知れない」という意味になる。?Sizedのみに可能。?Sizedのときは参照&を使う。実行時にしかサイズを知れない型は参照しかありえないから。

fn generic<T: ?Sized>(t: &T) {
    // --snip--
}

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux

前回まで