文法

変数宣言

let x : i32 = 1;
let y = 1; // 型推論
let mut z = 1; // 変更可能な値
const int x = 1;
const auto y = 1;
int z = 1;

RustのmutとC++の非constはほぼ同じ意味をもつ。

参照

let x : i32 = 1;
let y : &i32 = &x;
let z : &&i32 = &&x;
let zz : &i32 = &&x; // 参照の参照は参照に潰すことができる (Deref の型強制)
assert_eq!(x, *y); // 参照の解決
assert_eq!(x, **zz);
const int x = 1;
const int& y = x;
const int& z = y; // 参照の参照は参照

C++ではTとT&とで互いに暗黙の型変換が発生するが,
Rustでは& : T -> &Tと * : &T -> Tで明示的に変換する必要がある。

参照先が変更可能な参照

let x : i32 = 1;
{
    let y : &mut i32 = &mut x; // &mut: T -> &mut T
    *y = 5;
}
assert_eq!(x, 5);
int x = 1;
{
    int& y = x;
    y = 5;
}

&mut参照は, 参照先の値を変更できる

mut参照の制限

let mut x : i32 = 1;
let y : &i32 = &x; // OK
let z : &i32 = &x; // OK
// let w : &mut i32 = &mut x // NG

Rustではある値(T)にすでに参照(&T)またはmut参照(&mut T)がある時,
新しくmut参照(&mut T)は作れない。

これは主にデータレースを防ぐため。

関数宣言

fn plus(x : i32, y : i32) -> i32 {
    x + y // 式の結果を返す場合 ; をつけない。 つけると () を返す
}

fn say_hello() { // 省略すると返り値は ()
    println!("hello");
}
//c++
i32 plus(int x, int y) {
    return x + y;
}

void say_hello() {
    std::cout << "hello" << std::endl;
}

Hello, world

fn main() {
    println!("Hello, world");
}
#include <iostream>
int main() {
    std::cout<< "Hello, world" << std::endl;
}

制御構造

if / if let

let res = if x == 3 {
    -3
} else if x == 2 {
    -2
} else {
    0
}
int res;
if (x == 3) {
    res = -3;
} else if (x == 2) {
    res = -2;
} else {
    res = 0;
}

パターンマッチに成功する時ブロックを実行

let x = Some(3);
if let Some(v) = x {
    assert_eq!(v, 3);
}
ない

Rustにしかないやつ。Goとかにある条件式前束縛とは異なる

while / while let

let mut x = 5;
while x != 0 {
    x -= 1; // デクリメントはない
}
int x = 5
while (x != 3) {
    x--;
}
while if Some(v) = x {

}
ない

無限ループ

loop {
}
while (true) {
}

基本型

備考RustC++整数型i8, i16, i32, i64int8_t, int16_t …@(2), 2i32 …(2, 2l …)非負整数型u8, u16, u32, u64uint8_t, uint16_t …@2u32 …(2u)ポインタサイズ整数isize, usizeintptr_t, uintptr_t@2isize, 2usize
小数型f32, f64提案中(?) double@2.0f32, 2.0f64(2.0, 2.0ld …)論理値型boolbool@true, falsetrue, false文字型charchar32_t@'a', 'あ'U'a', U'あ'固定長配列型[T; N]T[]@[0, 1], [2; 3]{1, 2}, ({2, 2, 2})スライス&[T]
@arr[1..3] arr[..]
タプル(T, U, V)tuple<T, U, V>@(1, 'a', 1.0f32)make_tuple(1, 'a', 1.0)()void@()
参照&T, &mut Tconst T &, T &@&x, &mut x
生ポインタ*const T, *mut Tconst T *, T *@&x as *const i32&x

構造体

struct User {
    name: String,
    age: u64,
}
let u : User = User { name: String::from("Alice"), age: 17 };
assert_eq!(u.age, 17);
struct User {
    string: name,
    uint64_t: age
}
cosnt User u { "Alice", 17 };

メソッド

impl User {
    fn hello(&self) { // self, &self, &mut self の3パターンある。
        println!("I am {}.", self.name);
    }
}
let u : User = User { name: String::from("Alice"), age: 17 };
u.hello();
struct User {
    /*...*/
    hello() {
        std::cout << "I am " << this->name, << "." << std::endl;
    }
}
cosnt User u { "Alice", 17 };
u.hello();

型メソッド

impl User {
    fn me(age : u64) -> Self {
        User { name: String::from("Alice"), age: me }
    }
}
assert_eq!(User::me(10).name, String::from("Alice"));
struct User {
    /*...*/
    static User me (int age) {
        return User{ "Alice", 17 }
    }
}

演算子オーバオーロード

impl PartialEq<Self> for User {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name && self.age == other.age
    }
}

let u : User = User { name: String::from("Alice"), age: 17 };
let v : User = User { name: String::from("Alice"), age: 17 };
assert!(u == v);
struct User {
    /*...*/
    bool operator==(const User& that) const {
        return this.name == that.name && this.age == this.age;
    }
}

User v{"A", 17}, u{"A", 17};
v == u;

なお #[derive(PartialEq)] で自動生成される。

列挙体

enum IpAddrKind {
    V4,
    V6,
}
let ip : IpAddrKind = IpAddrKind::V4;
enum IpAddrKind {
    V4,
    V6
}
IpAddrKind ip = V4;

直積型

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Color(i32, i32, i32),
}
let mes : Message = Message::Move{ x: 1, y: 2 };
let mes = Message::Color(0, 1, 2);
ない

パターンマッチ

let s = match mes {
    Message::Move => "move",
    Message::Color => "color",
    _ => "other",
}
ない

パターンマッチで参照を得る, 外す

let mut x : i32 = 1;

// 以下の文はブロックで囲んでいる
{ let ref y : i32 = x; } // 参照を得る y : &i32
{ let y : &i32 = &x; } // 上と同じ

{ let ref mut z : i32 = x; } // 変更可能参照を得る z : &mut i32
{ let z : &mut i32 = &mut x; } // 上と同じ

{ let (ref y, ref z) : (i32, i32) = (1, 2); } // パターンマッチで使う y, z : &32

{ let &r : &i32 = &x; } // &にマッチすると参照が外れる r : i32
{ let r : i32 = x; } // 上と同じ

ref, ref mutパターンは, 参照を得るパターン

&, &mutパターンは, 参照を外すパターン

トレイト

演算子オーバーロード

    • 算術演算子: Add, Sub , Neg , Mul , Div , Rem

他の演算子: Not , BitAnd , BitOr , BitXor , Shl , Shr

配列参照: Index, IndexMut

関数呼び出し: Fn, FnMut, FnOnce

C++ではoperator

デバッグ出力

println!(“Display {}”, v): Display 簡易

println!(“Debug {:?}”, v): Debug 詳細

C++ではoperator<<

コピー・ムーブ

Rustでは束縛する時にコピーするかムーブするかは, その型にCopyトレイトが実装されているかに拠る。

コピー

let x : i32 = 1;
let y = x; // i32はCopyトレイトを実装しているのでコピー
println!("{}", x); // OK
int x = 1;
int y = x;

ムーブ

let x : &mut i32 = &mut 1; // &mut 32はCopyトレイトを実装していない
let y = x; // ムーブ
//println!("{}", x); // NG
int x = std::make_unique<int>(x);
auto y = std::move(x);

複製

Copyが実装されていないくても, Cloneが実装されていれば.clone()で複製できる

let x = String::from("str"); // StringはCopyを実装していない
let y = x.clone(); // 複製する
println!("{:?}", x); // OK

let x = String::from("str"); // StringはCopyを実装していない
let y = x; // ムーブする xは使えなくなる
//println!("{:?}", x); // NG

デストラクタ

struct Obj { s: i32 }
impl Drop for Obj {
    fn drop(&mut self) {
        println!("Droped {}.", self.s);
    }
}

{ let _x = Obj { s: "hey" }; }
struct Obj {
    int s;
    Obj(int s):s(s_){}
    ~Obj() {
        std::cout << "Droped " << this.s << std::endl;
    }
}

{ Obj x(1); }

デフォルトオブジェクト

impl User {
    fn default() -> Self {
        User{name: String::default(), age: u64::default() }
    }
}

let u : User = User::default()
// デフォルトコンストラクタ
User u;

Error

Hash

Into

impl Into<u64> for User {
    fn into(self) -> u64 {
        self.age
    }
}
let u : User = User{ name: String::from("Alice"), age: 32 };
let age : u64 = u.into();
struct User {
    /* ... */
    operator int () {
        return this->age;
    }
}

From

impl From<i32> for User {
    fn from(age : u64) -> Self {
        User { name: String::from("Alice"), age: age }
    }
}

let u : User = User::from(32);
struct User {
    /* ... */
    User(int age) {
        return User{ "Alice", age };
    }
}

User u = 32;

参照の暗黙の型変換(型強制)

impl Deref for User {
    fn deref(&self) -> &u64 {
        &self.age
    }
}

let u : User = User{ name: String::from("Alice"), age: 32 };
let refu : &User = &u;
let age : &u64 = &u;

Delefが実装されている時, 参照は暗黙の型変換が起きる。
参考: RustのDerefトレイトによる挙動を確認してみた

AsRef / AsMut

Borrow / BorrowMut

データ構造

基本データ構造

以下途中

array

slice

tuple

vec

無名関数

メモリ管理

ポインタ

その他

入出力