文法
変数宣言
rust
let x : i32 = 1;
let y = 1; // 型推論
let mut z = 1; // 変更可能な値
c++
const int x = 1;
const auto y = 1;
int z = 1;
Rustのmut
とC++の非const
はほぼ同じ意味をもつ。
参照
rust
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);
c++
const int x = 1;
const int& y = x;
const int& z = y; // 参照の参照は参照
C++ではT
とT&
とで互いに暗黙の型変換が発生するが,
Rustでは& : T -> &T
と * : &T -> T
で明示的に変換する必要がある。
参照先が変更可能な参照
rust
let x : i32 = 1;
{
let y : &mut i32 = &mut x; // &mut: T -> &mut T
*y = 5;
}
assert_eq!(x, 5);
c++
int x = 1;
{
int& y = x;
y = 5;
}
&mut
参照は, 参照先の値を変更できる
mut参照の制限
rust
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
)は作れない。
これは主にデータレースを防ぐため。
関数宣言
rust
fn plus(x : i32, y : i32) -> i32 {
x + y // 式の結果を返す場合 ; をつけない。 つけると () を返す
}
fn say_hello() { // 省略すると返り値は ()
println!("hello");
}
c++
//c++
i32 plus(int x, int y) {
return x + y;
}
void say_hello() {
std::cout << "hello" << std::endl;
}
Hello, world
rust
fn main() {
println!("Hello, world");
}
c++
#include <iostream>
int main() {
std::cout<< "Hello, world" << std::endl;
}
制御構造
if / if let
rust
let res = if x == 3 {
-3
} else if x == 2 {
-2
} else {
0
}
c++
int res;
if (x == 3) {
res = -3;
} else if (x == 2) {
res = -2;
} else {
res = 0;
}
パターンマッチに成功する時ブロックを実行
rust
let x = Some(3);
if let Some(v) = x {
assert_eq!(v, 3);
}
c++
ない
Rustにしかないやつ。Goとかにある条件式前束縛とは異なる
while / while let
rust
let mut x = 5;
while x != 0 {
x -= 1; // デクリメントはない
}
c++
int x = 5
while (x != 3) {
x--;
}
rust
while if Some(v) = x {
}
c++
ない
無限ループ
rust
loop {
}
c++
while (true) {
}
型
基本型
備考 | Rust | C++ |
---|---|---|
整数型 |
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 |
構造体
rust
struct User {
name: String,
age: u64,
}
let u : User = User { name: String::from("Alice"), age: 17 };
assert_eq!(u.age, 17);
c++
struct User {
string: name,
uint64_t: age
}
cosnt User u { "Alice", 17 };
メソッド
rust
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();
c++
struct User {
/*...*/
hello() {
std::cout << "I am " << this->name, << "." << std::endl;
}
}
cosnt User u { "Alice", 17 };
u.hello();
型メソッド
rust
impl User {
fn me(age : u64) -> Self {
User { name: String::from("Alice"), age: me }
}
}
assert_eq!(User::me(10).name, String::from("Alice"));
c++
struct User {
/*...*/
static User me (int age) {
return User{ "Alice", 17 }
}
}
演算子オーバオーロード
rust
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);
c++
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)]
で自動生成される。
列挙体
rust
enum IpAddrKind {
V4,
V6,
}
let ip : IpAddrKind = IpAddrKind::V4;
c++
enum IpAddrKind {
V4,
V6
}
IpAddrKind ip = V4;
直積型
rust
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);
c++
ない
パターンマッチ
rust
let s = match mes {
Message::Move => "move",
Message::Color => "color",
_ => "other",
}
c++
ない
パターンマッチで参照を得る, 外す
rust
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
トレイトが実装されているかに拠る。
コピー
rust
let x : i32 = 1;
let y = x; // i32はCopyトレイトを実装しているのでコピー
println!("{}", x); // OK
int x = 1;
int y = x;
ムーブ
rust
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()
で複製できる
rust
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
デストラクタ
rust
struct Obj { s: i32 }
impl Drop for Obj {
fn drop(&mut self) {
println!("Droped {}.", self.s);
}
}
{ let _x = Obj { s: "hey" }; }
c++
struct Obj {
int s;
Obj(int s):s(s_){}
~Obj() {
std::cout << "Droped " << this.s << std::endl;
}
}
{ Obj x(1); }
デフォルトオブジェクト
rust
impl User {
fn default() -> Self {
User{name: String::default(), age: u64::default() }
}
}
let u : User = User::default()
cpp
// デフォルトコンストラクタ
User u;
Error
Hash
Into
rust
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();
c++
struct User {
/* ... */
operator int () {
return this->age;
}
}
From
rust
impl From<i32> for User {
fn from(age : u64) -> Self {
User { name: String::from("Alice"), age: age }
}
}
let u : User = User::from(32);
c++
struct User {
/* ... */
User(int age) {
return User{ "Alice", age };
}
}
User u = 32;
参照の暗黙の型変換(型強制)
rust
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<Target = U>
が実装されている時, 参照は暗黙の型変換が起きる。
参考: RustのDerefトレイトによる挙動を確認してみた
AsRef / AsMut
Borrow / BorrowMut
データ構造
基本データ構造
以下途中
array
slice
tuple
vec