Rustの`?`クエスチョンマーク2

最近Rust 勉強中です。

Rustのクエスチョンマーク(?) - c_leaf.blog
去年もRustの?について調べた時のメモがわりの記事を書いていたのですが
うまく理解できていなかったのでもう一度調べて書き直したいと思います。

rustc 1.21.0 (3b72af97e 2017-10-09)です。

下記はtxtファイルから中身を読み込む処理です。

let mut file = File::open("./hello.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;

?が出てきています。

このままmain関数に書くとエラーが起きます。

fn main() {
    let mut file = File::open("./hello.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
}
/*
  |
  | let mut file = File::open("./hello.txt")?;
  |             ---------------------------------
  |           |
  |           the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`)
  |           in this macro invocation
  |
*/

? マークはResultを返す関数の中だけで使えるよ!でしょうか?

その通りでこの?マークは
関数の中でResultに対して使います。
Errが上がった場合すぐにErrをreturn、
Okが上がった場合処理を続行します。

こんな感じ

// read_file  read_file2は同じ処理
//?を使わない版
fn read_file() -> Result<String> {
    let mut file = match File::open("./hello.txt") {
        Ok(file) => file,
        Err(e) => return Err(e)
    };

    let mut contents = String::new();

    match file.read_to_string(&mut contents) {
        Ok(_) => {},
        Err(e) => return Err(e)
    }

    Ok(contents)
}

//?版
fn read_file2() -> Result<String> {
    let mut file = File::open("./hello.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

//これらを呼び出すときは
fn main() {
    // unwrapしちゃったり
    let str1 = read_file().unwrap();
    let str2 = read_file2().unwrap();

    // errorハンドリングしちゃったり
    match read_file() {
        Ok(src) => println!("{}", src),
        Err(err) => println!("{}", err)
    }
    match read_file2() {
        Ok(src) => println!("{}", src),
        Err(err) => println!("{}", err)
    }
}


参考にしました。
rust - What is this question mark operator about? - Stack Overflow

Rustでスレッドを使う

Rustでテトリスを作っています。

基本的な部分はできたのですが、
Rustの所有権のおかげでマルチスレッドプログラミングを悩ませてきます。

totem3.hatenablog.jp

ありがとうございます。
すごくわかりやすい。
こうやって自分の知識を公開していくプログラマの文化は好きです。

メモがわりの記事でした:)

vimの画面サイズ変更をもっと楽に

vimの画面サイズをもっと簡単に変更する方法を探していたところ
すぐに見つかりました。

しかもめっちゃ使いやすい。。。

Vimでウィンドウサイズの変更を簡単・高速にするプラグイン - Qiita
github.com


やっぱりいいですよね。
vim

嫌いなjavaに入門してみた。

私はプログラミング独学です。
一番最初に手に取った本がJavaでしたが
とても難しくてトラウマになっていました。

androidアプリもかけるし
いまさらですがJava入門します。。。

// Main.java
public class Main {
      public static void main(String[] args) {
            Fib f = new Fib();
            System.out.println(f.calculate(30));
      }
}

class Fib {
      void fib() {
      }

      public int calculate(int num) {
            if(num < 2) {
                  return num;
            }else{
                  return calculate(num-2) + calculate(num-1);
            }
      }
}

クラス名とファイル名は一緒でなければダメなのですね。。。
Mainクラス内に関数書いたら
static関数にしろと言われました(そりゃそうだけど)

Rustで遺伝的アルゴリズム

Rust 1.23.0です
遺伝的アルゴリズム書いてみました。

//src/main.rs
extern crate gene;
use gene::{colony, individual};

fn main() {
    let mut generations = colony::Colony::init_colony();
    let mut i = 0;

    loop {
        generations = generations.reviews();
        // std::thread::sleep(std::time::Duration::from_secs(1));

        generations.show();
        if colony::max_point(generations.get_colony(), 0) >= individual::GENE_COUNT as u32 {
            println!("HI");
            break;
        }
        generations = generations.delete()
            .make_children()
            .mutations();
        i += 1;
    }
}
//src/colony.rs
use individual::Individual;
use rand;
use rand::distributions::{IndependentSample, Range};

const GENERATIONS: usize = 20;
const DESTROY: usize = 5;

pub struct Colony {
    colony: Vec<Individual>
}

impl Colony {

    //初期化
    pub fn init_colony() -> Self {
        let mut colony: Vec<Individual> = Vec::new();
        for _ in 0..GENERATIONS {
            colony.push(Individual::init_gene());
        }
        Self {
            colony: colony
        }
    }

    pub fn show(&self) {
        println!("==============================");
        for i in 0..self.colony.len() {
            self.colony[i].show();
        }
    }

    pub fn get_colony(&self) -> Vec<Individual> {
        self.colony.clone()
    }

    // 全ての個体について評価する
    pub fn reviews(&self) -> Self {
        let mut colony = self.colony.clone();
        for i in 0..self.colony.len() {
            colony[i] = colony[i].review();
        }
        Self {
            colony: colony
        }
    }

    // ポイントの低い個体は削除
    pub fn delete(&self) -> Self {
        let mut colony = self.colony.clone();
        for _ in 0..DESTROY {
            let mut min_key = 0;
            let mut min_point = self.colony[0].get_point();
            for i in 1..colony.len() - 1 {
                let point = self.colony[i].get_point();
                if min_point > point {
                    min_key = i;
                    min_point = point;
                }
            }
            colony.remove(min_key);
        }
        Self {
            colony: colony
        }
    }

    pub fn make_children(&self) -> Self {
        let mut rnd = rand::thread_rng();
        let range = Range::new(0, GENERATIONS - DESTROY - 1);
        let mut colony = self.colony.clone();
        for _ in 0..DESTROY {
            let father = colony.get(range.ind_sample(&mut rnd)).unwrap().clone();
            let mother = colony.get(range.ind_sample(&mut rnd)).unwrap().clone();
            colony.push(Individual::make_child(father, mother));
        }
        Self {
            colony: colony
        }
    }

    // 突然変異させる
    pub fn mutations(&self) -> Self {
        let mut colony = self.colony.clone();
        for i in 0..self.colony.len() {
            if Range::new(0, 15).ind_sample(&mut rand::thread_rng()) == 1 {
                colony[i] = colony[i].mutation();
            }
        }
        Self {
            colony : colony
        }
    }
}


pub fn max_point(colony: Vec<Individual>, max: u32) -> u32 {
    let mut colony = colony.clone();
    if colony.len() > 0 {
        let point = colony.pop().unwrap().get_point();
        if max < point {
            max_point(colony, point)
        } else {
            max_point(colony, max)
        }
    }else{
        max
    }
}
//src/individual.rs
use rand;
use rand::distributions::{IndependentSample, Range};

pub const GENE_COUNT: usize = 18;
const CORRECT_GENE: [char; GENE_COUNT] = ['c', 'a', 'r', 'a', 'm', 'e', 'l', 'f', 'r', 'a', 'p', 'p', 'u', 'c', 'h', 'i', 'n', 'o'];
const ALPHABET: [char; 26] = [
    'a', 'b', 'c', 'd', 'e',
    'f', 'g', 'h', 'i', 'j',
    'k', 'l', 'm', 'n', 'o',
    'p', 'q', 'r', 's', 't',
    'u', 'v', 'w', 'x', 'y', 'z'
];

#[derive(Clone)]
pub struct Individual {
    point: u32,
    gene: [char; GENE_COUNT]
}


impl Individual {
    pub fn get_point(&self) -> u32{
        self.point
    }

    pub fn get_gene(&self) -> [char; GENE_COUNT] {
        self.gene
    }

    pub fn show(&self) {
        for i in self.gene.iter() {
            print!("{}", i);
        }
        println!(" - {}", self.point);
    }

    pub fn init_gene() -> Self {
        let mut gene = ['a'; GENE_COUNT];
        let range = Range::new(0, ALPHABET.len());
        for i in 0..gene.len() {
            gene[i] = ALPHABET[range.ind_sample(&mut rand::thread_rng())] as char;
        }

        Self {
            point: 0,
            gene: gene
        }
    }

    pub fn review(&self) -> Self {
        let mut point = 0;
        for i in 0..self.gene.len() {
            if self.gene[i] == CORRECT_GENE[i] {
                point += 1;
            }
        }

        Self {
            point: point,
            gene: self.gene
        }
    }

    pub fn mutation(&self) -> Self {
        let range: Range<usize> = Range::new(0, GENE_COUNT);
        let mut rng = rand::thread_rng();
        let rnd = range.ind_sample(&mut rng);
        let mut gene = self.gene;
        gene[rnd] = ALPHABET[range.ind_sample(&mut rng)] as char;
        Self {
            point: 0,
            gene: gene
        }
    }

    // 新しい個体を作る
    pub fn make_child(mother: Self, father: Self) -> Self {
        let cross_point = Range::new(0, GENE_COUNT).ind_sample(&mut rand::thread_rng());
        let mut gene = ['a'; GENE_COUNT];

        for i in 0..GENE_COUNT {
            if i > cross_point {
                gene[i] = mother.gene[i];
            }else{
                gene[i] = father.gene[i];
            }
        }
        Self {
            point: 0,
            gene: gene
        }
    }
}

なんか少し微妙かも
全て揃うまで結構かかります。。。

Nimでライフゲーム

nimでライフゲームを作って見ました。
コンパイル早くていい!!

import random

const
  COUNT: int = 100
  PIONEER: int = 200

type
  # enumの宣言 pureをつけると
  # Live -> errorになる
  # Status.Live -> okになるらしい
  Status {.pure.} = enum
      Live
      Death

  #多次元配列はこんな感じ?
  Cells = array[Count, array[COUNT, Status]]
  Point = tuple[x: int, y: int]
  Field = ref object of RootObj
    cells: Cells
    next_cells: Cells


# 関数宣言
# ここで宣言しておくと順番が後でも呼べるようになる
proc init_cells(): Cells
proc init_field(): Field
proc write(field: Field)
proc random_birthday(field: var Field)
proc get_neighbors_count(field: Field, point: Point): int
proc decide_life(field: var Field, point: Point)
proc live_cell(field: var Field, point: Point)
proc death_cell(field: var Field, point: Point)
proc is_under_population(count: int): bool
proc is_over_population(count: int): bool
proc is_just_population(count: int): bool
proc is_over0(num: int): bool
proc is_under_count(num: int): bool
proc is_exists(field: Field, point: Point): bool

# fieldオブジェクトの初期化
proc init_field(): Field =
  let cells = init_cells()
  return Field(cells: cells, next_cells: cells)

# cellsの初期化
proc init_cells(): Cells =
  var cells: array[COUNT, array[COUNT, Status]]
  for x in countup(0, COUNT-1):
    for y in countup(0, COUNT-1):
      cells[x][y] = Status.Death
  cells

#現在の状況を描画する
proc write(field: Field) =
  for x in countup(0, COUNT - 1):
    for y in countup(0, COUNT - 1):
      let cell = field.next_cells[x][y]
      field.cells[x][y] = cell
      case cell
        of Status.Live:
          write(stdout, "o ")
        of Status.Death:
          write(stdout, "_ ")
    echo("")

# 最初からいる生物をランダムに発生させる
# dot(.)でアクセスするとdotの前が第一引数になるらしい
# field.random_birthday() === random_birthday(field)?
# 多分 varで引数を指定するとミュータブルになる
proc random_birthday(field: var Field) =
  for i in countup(0, PIONEER):
    field.next_cells[random(COUNT-1)][random(COUNT-1)] = Status.Live

#周辺のcellの個数を取得
proc get_neighbors_count(field: Field, point: Point): int =
  var result = 0
  let x = point.x
  let y = point.y
  if is_over0(x-1) and is_over0(y-1) and field.is_exists((x-1, y-1)): result += 1
  if is_over0(y-1) and field.is_exists((x, y-1)): result += 1
  if is_under_count(x+1) and is_over0(y-1) and field.is_exists((x+1, y-1)): result += 1
  if is_over0(x-1) and field.is_exists((x-1, y)): result += 1
  if is_under_count(x+1) and field.is_exists((x+1, y)): result += 1
  if is_over0(x-1) and is_under_count(y+1) and field.is_exists((x-1, y+1)): result += 1
  if is_under_count(y+1) and field.is_exists((x, y+1)): result += 1
  if is_under_count(x+1) and is_under_count(y+1) and field.is_exists((x+1, y+1)): result += 1
  result

#人生を決める
proc decide_life(field: var Field, point: Point) =
  let neighbors_count = field.get_neighbors_count(point)
  if field.is_exists(point):
    if is_under_population(neighbors_count) or is_over_population(neighbors_count):
      field.death_cell(point)
  else:
    if is_just_population(neighbors_count):
      field.live_cell(point)

#cellを生む
proc live_cell(field: var Field, point: Point) =
  field.next_cells[point.x][point.y] = Status.Live

#cellを殺す
proc death_cell(field: var Field, point: Point) =
  field.next_cells[point.x][point.y] = Status.Death

# 過疎か判断
proc is_under_population(count: int): bool =
  #pythonに似ていて && ||はないかも
  count == 0 and count == 1

# 過密か判断
proc is_over_population(count: int): bool =
  count >= 4

#ちょうどいいか判断
proc is_just_population(count: int): bool =
  count == 3

proc is_over0(num: int): bool =
  num >= 0

proc is_under_count(num: int): bool =
  num < COUNT

#cellが存在しているか
proc is_exists(field: Field, point: Point): bool =
  field.cells[point.x][point.y] == Status.Live

proc main() =
  randomize()
  var field = init_field()
  field.random_birthday()
  field.write()
  while readLine(stdin) != "q":
    for x in countup(0, COUNT-1):
      for y in countup(0, COUNT-1):
        field.decide_life((x,y))
    field.write()

main()

Nim でふぃぼなっち

普通に書いたらこんな感じ?

proc fib(num: uint): uint =
  if num < 2:
    return num
  else:
    return fib(num-2) + fib(num-1)

for i in countup(0, 10):
  echo fib(uint(i))

私はこっちの方で好きです。

proc fib2(num: uint): uint =
  return case num
    of 0, 1: num
    else: fib2(num-2) + fib2(num-1)

for i in countup(0, 10):
  echo fib2(uint(i))