RustとRubyの違い


Mut


    Ruby: 変数は値変えられます
hoge = 1
hoge = 2
p hoge

# 結果: => 2

    Rust: 変数は値変更不可(immutable)
fn main() {
  let hoge = 1;
  hoge = 2;

  <!-- 
    ビルドエラー 
    error[E0384]: cannot assign twice to immutable variable `hoge` 
  -->


  println!("Hoge {:}", hoge);
}


    Rust: 変数の値変更したい場合、mutを付けないといけません
fn main() {
  let mut hoge = 1;
  hoge = 2;

  println!("Hoge {:}", hoge);
  <!-- 結果: Hoge 2 -->
}


    Ruby: 変数の型がありません、コンパイラーは値から型を付けます (PHPなどと同じ)
hoge = "as"
a.class
# => String

hoge = 12
hoge.class
# => Integer

    Rust: 変数の型は変更出来ません、(C, Java, Cotlin, Swiftなどと同じ)
fn main() {
  let mut hoge = 1; 
  <!-- Hoge変数は `&str` 型になります-->

  hoge = "hola";
  // ビルドエラー 
  // error[E0308]: mismatched types
  //  |
  //  |     hoge = "hola";
  //  |            ^^^^^^ expected integer, found `&str`

  println!("Hoge {:}", hoge);
}


変数のReference


    Rustはreferenceがあります。(Cと同じ)
fn main() {

  let a: u8 = 10;
  let b = &a;
  println!("Pointer a: {:p}", b);
  println!("Value   a: {}", a);
  println!("Value   b: {}", b);
}

  // Pointer a: 0x7ffd469b821f
  // Value   a: 10
  // Value   b: 10
}

    Ruby: 全部はobjectなので、変数はPointerです。Rustの書き方が存在しません
a = 12
b = &a

# コンパイラーエラー
# SyntaxError ((irb):23: syntax error, unexpected &)

    RubyのReference
class Hoge attr_accessor :name end
hoge = Hoge.new
fuga = hoge

hoge.name = "hoge"
p fuga.name
# 結果
# => "hoge"

fuga.name = "fuga"
p hoge.name
# 結果
# => "fuga"


質問1

fn main() {

  let mut a: u8 = 10;
  let b = &mut a;

  a = 11;
  println!("Value a: {:}", a);
}

→ エラーがありますか?


質問1の答え

    エラーはありません

質問2

fn main() {

  let mut a: u8 = 10;
  let b = &mut a;

  a = 11;
  println!("Value b: {:}", b);
}

→ 結果はどうなりますか?


質問2の答え

    エラー発生します
 --> src/main.rs:7:3
  |
7 |   a = 11;
  |   ^
  |
  = note: `#[warn(unused_assignments)]` on by default
  = help: maybe it is overwritten before being read?

error[E0506]: cannot assign to `a` because it is borrowed
 --> src/main.rs:7:3
  |
5 |   let b = &mut a;
  |           ------ borrow of `a` occurs here
6 |   
7 |   a = 11;
  |   ^^^^^^ assignment to borrowed `a` occurs here
8 |   println!("Value b: {:}", b);
  |                            - borrow later used here

error: aborting due to previous error; 1 warning emitted


Borrowing と Ownership


    Rubyでオーナーとういう概念がない、複数変数はひとつのデータに参照するときに、どの変数でもデータ変更できます
class Hoge attr_accessor :name end
hoge = Hoge.new
fuga = hoge

hoge.name = "hoge"
p fuga.name
# 結果
# => "hoge"

fuga.name = "fuga"
p hoge.name
# 結果
# => "fuga"


    Rust: 一つの変数だけデータ変更できます。
struct Hoge {
    count: i32,
}
fn main() {
    let mut hoge = Hoge {count: 1};
    let fuga = &mut hoge;
    fuga.count = 2;
    println!("Hoge count: {:}", hoge.count);
    hoge.count = 3;
    println!("Hoge count: {:}", fuga.count);

    //     error[E0502]: cannot borrow `hoge.count` as immutable because it is also borrowed as mutable
    //   --> src/main.rs:8:33
    //    |
    // 6  |     let fuga = &mut hoge;
    //    |                --------- mutable borrow occurs here
    // 7  |     fuga.count = 2;
    // 8  |     println!("Hoge count: {:}", hoge.count);
    //    |                                 ^^^^^^^^^^ immutable borrow occurs here
    // 9  |     hoge.count = 3;
    // 10 |     println!("Hoge count: {:}", fuga.count);
    //    |                                 ---------- mutable borrow later used here

    // error[E0506]: cannot assign to `hoge.count` because it is borrowed
    //   --> src/main.rs:9:5
    //    |
    // 6  |     let fuga = &mut hoge;
    //    |                --------- borrow of `hoge.count` occurs here
    // ...
    // 9  |     hoge.count = 3;
    //    |     ^^^^^^^^^^^^^^ assignment to borrowed `hoge.count` occurs here
    // 10 |     println!("Hoge count: {:}", fuga.count);
    //    |                                 ---------- borrow later used here
}


Nil vs Option


    Ruby: どの変数でもnil付けられます
  x = 2;
  y = nil;

  print "x: #{x}, y: #{y}"
  # 結果
  # x: 2, y: => nil

    Rust: nilは存在しません → 代わりにデータがある・ないの型があります → Option

fn main() {
    let x: Option<u32> = Some(2);
    let y: Option<u32> = None;

    println!("x: {:?}, y: {:?}", x, y)
}


    • Rust OptionのNone = Rubyのnil

 

    RUst OptionのSome = RUbyのnilじゃない

    Ruby: Nilに関連するoperatorがありません
a = nil
b = a + 1
# NoMethodError (undefined method `+' for nil:NilClass)

    Rust: Optionに関連するoperatorもありません、ただOptionのデータで使うとときに、Noneをチェックしないといけません → 安全です
fn main() {
  let a: Option<u32> = Some(2);

  let value = match a {
    Some(v) => v,
    None => 0 
  };

  let b = value + 1;

  println!("b: {:}", b);
}

Result – エラーハンドリング


    エラーは外部APIまたは特別な処理の時に、エラー発生します。

例: FbApiError, ValidationError..


    Ruby: 関数開発の時にエラー気にしなくも開発出来ます

def call_api(endpoint, method)
   fb_client.call(endpoint, method) # エラーがある処理

   'API Done'
end


    Ruby: エラーハンドリングの時に開発者に決められます。

def call_api(endpoint, method)
  begin
    fb_client.call(endpoint, method)
  rescue => exception
    'API ERROR'
  end

  'API Done'
end


    Ruby: エラーハンドリングしないと関数が呼ばれるところにエラー投げます。
def call_api(endpoint, method)
   fb_client.call(endpoint, method) # エラーがある処理

   'API Done'
end

call_api("me", "GET") # fb_client.call でエラー発生したら、ここに止まります。

    Rust: 関数開発の時にエラーがあれば、Resultとうい型になります。
    pub async fn call_api(&self, endpoint: &str, method: &str) -> String{
        self.call(endpoint, method) // エラーがある処理

        "API DONE".to_owned()
    }

    Rust: Resultをみるとエラーがあるかどうか分かります。
    pub async fn call_api(&self, endpoint: &str, method: &str) -> String{
        return match self.call(endpoint, method) {
             Ok(value) => "API DONE".to_owned(),
             Err(error) => "API ERROR".to_owned()
        }
    }


    Rust: エラーハンドリングしないときに、エラー発生したら何も起こらない
    pub async fn call_api(&self, endpoint: &str, method: &str) -> String{
        await self.call(endpoint, method) // エラーがある処理

        "API DONE".to_owned()
    }

    pub async fn run(&self){
        await self.call_api("me", "GET") // .call でエラー発生しても、何も起こらない
    }

まとめ

    • Mut

 

 

    • Reference

 

    • Nil/Option

 

    Result
bannerAds