Rust入門してみた
自己紹介
- @takatori
- チームラボ株式会社
- 2年目
- Rust, JavaScript, AWS
Rust
- システムプログラミング言語
- OSとかデバイスドライバとか書くやつ
- GCがないのにメモリ管理やってくれる
- 安全・速度・並列
- ゼロコスト抽象化
よくわからないけどすごそう
- メモリ安全性
- 代数データ型
- パターンマッチ
- トレイト
- マクロ
メモリ安全性
C言語のメモリ管理
- 安全なコードを書くのが難しい
- プログラマがメモリの確保・解放をする
- 脆弱性を埋め込んでしまう
- バッファーオーバーラン
- ダングリングポインタ
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *a = malloc(1);
free(a); // 開放
char *b = malloc(1);
*b = 'b';
*a = 'a'; // ダングリングポインタへの操作
printf("%c", *b); // "a" ("b"ではない!?)
}
GCがある言語のメモリ管理
- メモリ管理はガーベージコレクタが行ってくれる
- 参照されなくなった領域はGCが回収
- フルGCが走るとシステムが止まる
- フルGCが走るとシステムが止まる
- 参照されなくなった領域はGCが回収
Rustのメモリ管理
Rustは以下の3つの概念を用いることで
GC無しで安全なメモリ管理を提供する
- 所有権
- 借用
- ライフタイム
所有権
- Rustはリソースに対する束縛を一つに制限する
- 束縛が一つしかないのでダングリングポインタは発生しない
- 束縛がスコープから外れる時、リソースを解放する
fn foo() {
let v = vec![1, 2, 3]; // 変数束縛
let v2 = v; // 所有権がvからv2に変更される
println!("{}", v); // ここでvを参照しようとするとコンパイルエラー
}
// v2がスコープから外れるのでメモリも解放される
所有権を返す
// 値渡し、所有権も移る
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> i32){
// v1とv2についての作業を行う
42
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let answer = foo(v1, v2);
// 所有権が移動したのでv1、v2をここで使用するとコンパイルエラー
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
// v1とv2についての作業を行う
// 所有権と関数の結果を返す
(v1, v2, 42)
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let (v1, v2, answer) = foo(v1, v2);
借用
- 参照を取ることで所有権を借りることができる
- スコープから外れるときに所有権を返す
- リソースの割当は解除しない
// 所有権を借りる
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// v1とv2についての作業を行う
// 答えを返す
42
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let answer = foo(&v1, &v2);
// ここではv1とv2が使える!
ライフタイム
- 借用チェッカー
- 全ての借用に問題がないことを確認する仕組み
- 参照の有効なスコープのこと
{
let r;
{
let x = 1;
r = &x;
// ここまでがxの有効なスコープ
}
assert_eq!(*r, 1); // xのスコープ外で参照しているのでコンパイルエラー
}
代数的データ型
enum Option<T> {
None,
Some(T)
}
// ScalaのEitherみたいなやつ
enum Result<T, E> {
Ok(T),
Err(E),
}
enum Message {
Quit,
ChangeColor(i32, i32, i32),
Move { x: i32, y: i32 },
Write(String),
}
パターンマッチ
// x: i32
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
// x : Option<t>
match x {
None => false,
Some(_) => true
}
トレイト
trait HasArea {
fn area(&self) -> f64;
}
impl HasArea for i32 {
fn area(&self) -> f64 {
println!("this is silly");
*self as f64
}
}
5.area();
クロージャ
let plus_one = |x: i32| x + 1;
assert_eq!(2, plus_one(1));
ゼロコスト抽象化
- すべてコンパイル時に解決される
- 実行時にオーバーヘッドが存在しない
- C++並の速度が出る
その他
- 型推論
- hygienic macro
まとめ
- Rustたのしー
Rust入門してみた
By Satoshi Takatori
Rust入門してみた
- 936