文法
変数宣言
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
, i64
int8_t
, int16_t
…@(2
), 2i32
…(2
, 2l
…)非負整数型u8
, u16
, u32
, u64
uint8_t
, uint16_t
…@2u32
…(2u
)ポインタサイズ整数isize
, usize
intptr_t
, uintptr_t
@2isize
, 2usize
小数型
f32
, f64
提案中(?) double
@2.0f32
, 2.0f64
(2.0
, 2.0ld
…)論理値型bool
bool
@true
, false
true
, false
文字型char
char32_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 T
const T &
, T &
@&x
, &mut x
生ポインタ
*const T
, *mut T
const 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
データ構造
基本データ構造
以下途中