LoginSignup
20
17

More than 5 years have passed since last update.

RustとC++を比較

Last updated at Posted at 2017-11-01

文法

変数宣言

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++ではTT&とで互いに暗黙の型変換が発生するが,
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

無名関数

メモリ管理

ポインタ

その他

入出力

20
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
17