0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rustの基本2 一般的なプログラミングの概念

Last updated at Posted at 2022-12-15

3. 一般的なプログラミングの概念

3.1 変数と可変性

  • 前回の記事では、変数は標準でイミュータブル(不変)になると書いた
    それが以下

    // イミュータブル
    let val1: i32 = 5;
    
    // ミュータブル
    let mut val2: i32 = 5;
    
    val1 = 6 //コンパイルエラー
    val2 = 6 //OK
    

    再代入する場合は必ずletの後にmutをつける必要がある

  • 変数と定数の違い
    Rustはjsなどと同じよう、constで定数を定義することができる
    この定数は必ず型宣言が必要とのこと

    const MAX_POINTS: u32 = 100_000;
    
    • constとイミュータブルの違いは?
      どちらも不変であり、違いがないように見える。実際正確には把握していないが、調べてみると
      • letは型宣言が不要だがconstは必要
      • constはどんなスコープ(グローバルスコープ)でも定義可能というところ
  • シャドーイング

    前に定義した変数と同じ名前の変数を新しく宣言でき、 新しい変数は、前の変数を覆い隠します。Rustaceanはこれを最初の変数は、 2番目の変数に覆い隠されたと言い、この変数を使用した際に、2番目の変数の値が現れるということです。

    fn main() {
        let x = 5;
    
        let x = x + 1;
    
        {
            let x = x * 2;
            println!("The value of x in the inner scope is: {}", x);
        }
    
        println!("The value of x is: {}", x);
    }
    

    これはイミュータブルでも問題ない
    理由としては、let x = 5 でイミュータブルで宣言した後に、再度宣言しなおしているため、元のxという変数にx + 1を入れるのではなく、新しいxという変数に過去のxに1をプラスした値を入れているという感じ

    let mut x = 5;
    x = "This is String";
    

    このようにするとコンパイルエラーになる
    mutでミュータブルにしても元の型と違う値は入れることができない

3.2 データ型

  • Rustは静的型付け言語であり、すべての変数の型はコンパイル時に必ず判明している必要がある
  • 複数の型が予想される場合は型注釈をつけなければいけない
    let guess: u32 = "42".parse().expect("Not a number!"); 
    

スカラー型

Rustには主に4つのスカラー型があります: 整数、浮動小数点数、論理値、最後に文字です。

スカラーは簡単にいうと普通の数字。大きさのみを持っている
相対するものとしてベクトルというものがある
ベクトルは大きさに加え、方向があるもの

  • 整数型

    大きさ 符号付き 符号なし
    8-bit i8 u8
    16-bit i16 u16
    32-bit i32 u32
    64-bit i64 u64
    arch isize usize

    Rustでは8bitから最大64bitまでの整数を表現することが可能
    bitとは二進数で表されるものであり、8bitで1バイトとなる
    例として、8bitで表せる最大値は11111111255となる
    これを符号付きの場合は先頭の1bitが符号を表すため、1111111±127までの値を表せる
    isizeusizeはプログラムが動作しているアーキテクチャに依存するとのこと
    (32bitなら32bit、64bitなら64bit)

  • 浮動小数点型

    Rustにはさらに、浮動小数点数に対しても、2種類の基本型があり、浮動小数点数とは数値に小数点がついたもののことです。 Rustの浮動小数点型は、f32とf64で、それぞれ32ビットと64ビットサイズです。基準型はf64です。 なぜなら、現代のCPUでは、f32とほぼ同スピードにもかかわらず、より精度が高くなるからです。

    fn main() {
        let x = 2.0; // f64
    
        let y: f32 = 3.0; // f32
    }
    

    型を定義せずに小数を格納した場合は自動的にf64型になるらしい
    (速度が同じなら基本的に小数を使う際はf64型でいいかも)

  • 数値演算
    これはほかの言語と変わらないので飛ばす

  • 論理値型

    他の多くの言語同様、Rustの論理値型も取りうる値は二つしかありません: trueとfalseです。 Rustの論理値型は、boolと指定されます。

    fn main() {
        let t = true;
    
        let f: bool = false; // with explicit type annotation
                            // 明示的型注釈付きで
    }
    

    型宣言をしてもしなくても問題ないらしい
    たびたび型宣言をしなくても自動的に解釈してくれるとのこと

  • 文字型

    Rustには文字も用意されています。Rustのchar型は、 言語の最も基本的なアルファベット型

    fn main() {
        let c = 'z';
        let z = 'ℤ';
        let heart_eyed_cat = '😻';    //ハート目の猫
    }
    

    char型の場合はシングルクォテーションで囲うこと
    char型はユニコードのスカラー値を表している
    https://ja.wikipedia.org/wiki/Unicode%E4%B8%80%E8%A6%A7_0000-0FFF
    これだけの文字をchar型だけで表現することが可能

  • 複合型
    複合型というと少しわかりづらい感じはあるが、配列やタプルがそれにあたる

    • タプル型
      宣言は以下

      fn main() {
          let tup: (i32, f64, u8) = (500, 6.4, 1);
      }
      

      letのあとに変数名で、そのあとに型をひとつづつ書いていく(少しめんどくさそう)
      しかしこれらはほかの変数と同じく型宣言がなくてもOK

      fn main() {
          let tup = (500, 6.4, 1);
      
          let (x, y, z) = tup;
      
          println!("The value of y is: {}", y);
      }
      
      • アクセス方法
        let tup = (500, 6.4, 1);
        
        //上にあるように、最初に宣言して、その下でx, y, zという変数にそれぞれ独立させて入れる
        let (x, y, z) = tup;
        println!("The value of y is: {}", y);
        
        //配列のようにインデックス番号でアクセス
        println!("The value of y is: {}", tup.1);
        
    • 配列型
      ほかの言語と同じように宣言可能

      fn main() {
          let a = [1, 2, 3, 4, 5];
      }
      

      タプル型と違って、この配列の中のデータの型はすべて同じでなければいけない
      また、Rustの配列は一度宣言されたらサイズを伸ばすことも縮めることもできないので注意
      似たような型としてベクタ型というものがあるが、これは8章で解説されるらしい

3.3 関数

  • 続いては関数の書き方について

  • Rustはmain関数が実行時のエントリポイント(最初に走る処理)になっている

    fn main() {
        println!("Hello, world!");
    
        another_function();
    }
    
    fn another_function() {
        println!("Another function.");  // 別の関数
    }
    

    型の宣言はfnの後に関数名、引数といった感じで定義する
    関数名はスネークケースで定義するのが慣習(単語の間を_でつなぐ)

    • 似たようなものとしてキャメルケースがある(単語の変わり目を大文字で書く 例:anotherFunction)
      覚えておいて損はない

    引数がある場合は以下

    fn another_function(x: i32) {
        println!("The value of x is: {}", x);   // xの値は{}です
    }
    

    関数名のあとの()の中に変数名: 型といった書き方をする
    関数の引数は必ず型の宣言が必要とのこと

    • 戻り値のある関数
      戻り値に関しては少し特殊な部分がある
      戻り値がある関数は以下のように定義

      fn another_function() -> i32{
          5
      }
      
      //returnでも返せる
      fn another_function() -> i32{
          return 5;
      }
      

      アロー->のあとに戻り値の型を宣言
      これを見たときに、少しでもプログラミングをかじっている人はおかしいと思うかもしれないがRust的にはこれでOK
      Rustは戻り値がある関数を作成した時にreturn文を書かないと、最後に評価した値が戻り値となる特性を持っている(この場合は;は必要ない)
      (正直returnで明確に指定したほうが可読性があがるのでは?と思うがどうだろうか)

3.4 コメント

// これでコメントアウトになる

この程度のことしか書かれてないので飛ばす
ドキュメントコメントに関してはここでは解説されていない

3.5 制御フロー

  • これも少しわかりづらくかかれているが、ようはループやif文のこと

if文

fn main() {
    let number = 3;

    if number < 5 {
        println!("condition was true");       // 条件は真でした
    } else {
        println!("condition was false");      // 条件は偽でした
    }
}

if文はこんな感じ
条件式にかっこが必要ないところはpythonに近い

  • 三項演算子
    Rustもほかの言語同様三項演算子がある
    書き方は以下

    fn main() {
        let condition = true;
        let number = if condition { 5 } else { 6 };
    
        // numberの値は、{}です
        println!("The value of number is: {}", number);
    }
    

    これはifの後の条件式を評価して、trueだったらelseの手前の値、falseだったらelse以降の値がnumberに入ることになる
    この場合はnumberには5が入る

    fn main() {
        let condition = true;
    
        let number = if condition { 5 } else { "six" };
    
        println!("The value of number is: {}", number);
    }
    

    この場合はエラーになる
    評価した後に変数に入れる値の型は同一でなければならない
    先ほども言ったように、変数の型は単独でなければならないというルールに従っている

ループ処理

  • Rustのループ処理は、loop while forの三つが存在する
    • loop

      fn main() {
          loop {
              println!("again!");   // また
          }
      }
      

      loopはこのように書くことで無限にループさせることができる
      このloopを抜けるにはbreakを使う必要がある

      fn main() {
          let mut loops: i32 = 0;
          const LIMIT: i32 = 10;
          loop {
              if loops == LIMIT{
                  break;
              }
              println!("again!");   // また
              loops+=1;
          }
      }
      

      これで10回ループさせることができる

    • while

      fn main() {
          let mut number = 3;
      
          while number != 0 {
              println!("{}!", number);
      
              number -= 1;
          }
      
          // 発射!
          println!("LIFTOFF!!!");
      }
      

      これはよくあるwhileと同じなので飛ばす
      単純にwhileのあとの式が真の間は繰り返すだけ

    • for

      fn main() {
          let a = [10, 20, 30, 40, 50];
      
          for element in a {
              println!("the value is: {}", element);
          }
      }
      

      for文の基本はpythonと同じ仕組み
      この文だとelementの中には10, 20とaの値が順番に入っていく
      ループで一番多く使うのはこのfor文

      fn main() {
          for number in (1..4).rev() {
              println!("{}!", number);
          }
          println!("LIFTOFF!!!");
      }
      

      ここが少し特殊な書き方になる
      inの後を(1..4)のようにすることで範囲を表すことができる
      この場合は1以上4未満の間となる
      例えば1..=4とした場合は1以上4以下にすることも可能
      revメソッドは逆順に並べ替えてくれるメソッドらしい
      ちなみにこのnumberはミュータブルであり、ループの中で値を書き換えることが可能

      fn main() {
          for number in (1..4).rev() {
              println!("{}!", number+1);
          }
          println!("LIFTOFF!!!");
      }
      
      4!
      3!
      2!
      LIFTOFF!!!
      
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?