✏️

Rustの100本ノックを受けようとしているけど、なかなか進まない件

2024/02/20に公開

概要

Rustはじめました。
とりま、本などを数冊購入してみたものの、他の言語でも同じで…まあいつも通りなのだけど、前半の言語仕様の羅列のところで挫折、あわよくば、進んだところで、TODOを管理するツールとかができて「ほーん?」ってなって終わり…という繰り返し。
今回もそんな感じになりそうだな…と思ってたところ、100本ノックという儀式で言語の習得をする手があることを知りました。

なにしてる記事?目的は?

C言語向けの100本ノックのお題ページを元に、Rustで書いています。ページに正解の提示がないけど、書いて動かしてみて出力見本と同じならOKというゆるい方針でやってます。
まだ途中だけど、その過程で、課題用ファイル作成したり、実行のためのコマンド打ち込んだりするのがめんどいのでシェルスクリプト書いたので、Githubで公開します…という話
…をRustいじった感想などを含め書いています。

ここまでのあらすじ

まず、Amazonで検索して、良さげな書籍を買ったり、Kindle Unlimitedで購読したりしてましたが、ピンとはこないで、モチベーションは低下しておりました。
とりあえず、公式のサンプルとか眺めて加油するしか! ということで、公式サイトを見てみました(最初にみるべきですが…)。で、通称「The Book」と呼ばれているいい感じのチュートリアルがあり、しかも日本語版もきっちり整備されているということを知りました…。

https://doc.rust-jp.rs/book-ja/

ひとまず、数当てゲームまですすめて、そのあとはなんか難しそうなので、一旦動画で休憩。

https://www.youtube.com/watch?v=LW9hT0nY51Y
https://www.youtube.com/watch?v=a01nZTFVj6Q
https://www.youtube.com/watch?v=gDyk6OTSdto

とかみました。画面がぼやけてて、=と-や;と:の判別がつきにくかったのだけど、写経してでてくるエラーを読みつつ進めることで、ぼんやりわかってきた感じも。

The bookがそもそもエラーが出る前提でコードが提示されてて、エラー読むのに慣れてきてたというのと、なんかエラーの解決策とか表示されて、そのとおりにすると解決するパターンが多かったのも助かりポイントだったと思います。

とはいえ、まだちょっとThe Bookの後半は難しそうなので、他になにか…と探してみたら、以下を見つけました。

https://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocks.html

2024/2/20現在、絶賛取り組み中ということで、今の状況をサクッとメモに残しておこうと思います。

メモ

環境構築

前提として、以下のことが済んでいることとします

  • 作業場所の確保
    • mkdir work_rustとか。
  • Rustのインストール
    • curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • VSCodeのインストール
  • 100本ノック用のRustプロジェクトの作成
    • cargo init knock100
    • cd knock100
    • cargo run でHello worldが表示されればOK
  • Gitは省略
  • src/binの作成
    • mkdir src/bin
    • 100本ノックの課題ごとにプロジェクトを作らずに、ここにrsファイルを作ればOK
    • cargo run --bin xxxxxx でコンパイル&実行できる

感想

  • ファイル作るのめんどい
    • touch src/bin/xxxxxx.rs
  • 実行にいちいちコマンド打つのめんどい
    • cargo run --bin xxxxxx
  • 課題の差分が…
    • 前の課題をちょっと手直しする程度なので、ダレてくる。まあだからノックなのかもしらんけど。
  • VSCodeが勝手にコード書いてくれる
    • mainの{}の中にタブを打つとVSCodeが少し考えて、ほぼ確実に動くコードを提示してくれる。
    • 楽だけど、これいいのだろうか…とは思う。

終わったら

  • Tauri(クロスプラットフォームのGUIフレームワーク)
  • Bevy(ゲームエンジン)

とかに進みたい。
とりあえず、「めんどい」の解決のために書いたので、シェルの勉強にはなった。

  • 文字に色をつける
  • 入力待ち
  • ツールのインストール確認
  • 桁数や整数・文字列の判別
  • 文字列の一部削除

setup.sh

プロジェクトディレクリにおいて使います。
最初のノック番号と最後のノック番号を指定すると、main()の記述されたrsファイルをsrc/binの中に生成します。

#!/bin/bash

#------------------------#
# 100本ノック用のファイルを
# 生成するスクリプトです。
#------------------------#

#------------------------#
# 初期設定
#------------------------#

SCRIPT_VER=20240220-001

SCRIPT_DIR=$(cd $(dirname $(readlink $0 || echo $0));pwd -P)
MAKE_DIR="/src/bin"
FILE_NAME_PREF="knock100_"
FILE_NAME_END=".rs"

#------------------------#
# メイン
#------------------------#

echo "--==--==--==--==--==--==--==--==--==-- "
echo "-- "
echo -e "-- \033[1;32m100本ノック用のファイル生成ツール\033[0;39m"
echo "-- "
echo "-- Ver.${SCRIPT_VER}"
echo "-- "
echo "-- 以下のディレクトリにファイルを作成します。"
cd ${SCRIPT_DIR}${MAKE_DIR}
echo "-- ${SCRIPT_DIR}${MAKE_DIR}"
echo "-- "
echo "-- ファイル名パターン。"
echo "-- ${FILE_NAME_PREF}xxx${FILE_NAME_END}"
echo "-- "

if [ ! $srartNum ]; then
	echo "-- >>>>"
  echo -e "--  (^_^)ノ \033[1;36m生成をスタートするファイルの番号を入力してください。\033[0;39m"
  IS_WAIT=true
  while $IS_WAIT
  do
    read srartNum
    if [ ${#srartNum} -le 3 ] && [[ "$srartNum" =~ ^[0-9]+$ ]]; then
        IS_WAIT=false
    else
      echo -e "--  (^_^)ノ \033[1;33m3桁以内の整数値を入力してください。\033[0;39m"
    fi
  done
fi
FILE_NUM_START=$(printf "%03d\n" "${srartNum}")

if [ ! $stopNum ]; then
	echo "-- >>>>"
  echo -e "--  (^_^)ノ \033[1;36m生成する最後のファイルの番号を入力してください。\033[0;39m"
  IS_WAIT=true
  while $IS_WAIT
  do
    read stopNum
    if [ ${#stopNum} -le 3 ] && [[ "$stopNum" =~ ^[0-9]+$ ]]; then
      IS_WAIT=false
    else
      echo -e "--  (^_^)ノ \033[1;33m3桁以内の整数値を入力してください。\033[0;39m"
    fi
  done
fi
FILE_NUM_STOP=$(printf "%03d\n" "${stopNum}")

echo "-- "
echo "-- 以下のファイルを生成します。"
echo "-- ${FILE_NAME_PREF}${FILE_NUM_START}${FILE_NAME_END}${FILE_NAME_PREF}${FILE_NUM_STOP}${FILE_NAME_END}"
echo "-- "

if [ ! $doTaskimg ]; then
	echo -e "-- (^_^)ノ \033[1;31mファイルを生成しますか?\033[0;39m"
	echo "-- "
	echo "-- \033[1;33m [!] 未入力のままenterするとこの処理を回避します。\033[0;39m"
  echo "-- \033[1;36m y や yes など英数文字を入力してください。\033[0;39m"
fi
if [ ! $doTaskimg ]; then
	read doTaskimg
fi

for ((i=$srartNum; i < $stopNum+1; i++)); do
    myFile=${SCRIPT_DIR}${MAKE_DIR}/${FILE_NAME_PREF}$(printf "%03d\n" $i)${FILE_NAME_END}
    touch $myFile
    echo "// このファイルはスクリプトにより生成されました" >> $myFile
    echo "fn main() {" >> $myFile
    echo "" >> $myFile
    echo "}" >> $myFile
done

# 終了処理
echo "  "
echo "----- FINISH ------"
echo "  "
echo "--==--==--==--==--==--==--==--==--==-- "

exit

run.sh

プロジェクトディレクリにおいて使います。
src/binの中にあるノックプログラムの一覧が表示されるので、選択すると、コンパイルと実行(cargo run --bin xxxxxx)されます。
peco必要です。

#!/bin/bash

#------------------------#
# 100本ノック用のファイルを
# 指定して実行するスクリプトです。
#------------------------#

#------------------------#
# 初期設定
#------------------------#

SCRIPT_VER=20240220-001

SCRIPT_DIR=$(cd $(dirname $(readlink $0 || echo $0));pwd -P)
MAKE_DIR="/src/bin"
FILE_NAME_PREF="knock100_"
FILE_NAME_END=".rs"

#------------------------#
# メイン
#------------------------#

echo "--==--==--==--==--==--==--==--==--==-- "
echo "-- "
echo -e "-- \033[1;32m100本ノック用のファイル実行ツール\033[0;39m"
echo "-- "
echo "-- Ver.${SCRIPT_VER}"
echo "-- "
echo "-- 以下のディレクトリの100本ノックのファイルを実行します。"
cd ${SCRIPT_DIR}${MAKE_DIR}
echo "-- ${SCRIPT_DIR}${MAKE_DIR}"
echo "-- "
echo "-- 環境確認... "

# rustの確認
rust_ver=`rustc --version`
if [ $? -ne 0 ]; then
	echo "-- rustc Error"
	echo "-- [!実行不能] 「rustc」が実行できませんでした。"
	echo "-- [!実行不能] 「rustc/rust」がインストールされていません。"
	echo "-- [!実行不能] curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh を実行してください。"
	exit 1
else
	echo -n "-- Rust OK => "
  echo $rust_ver
fi
# cargoの確認
cargo_ver=`cargo --version`
if [ $? -ne 0 ]; then
	echo "-- Cargo Error"
	echo "-- [!実行不能] 「cargo」が実行できませんでした。"
	echo "-- [!実行不能] 「cargo/rust」がインストールされていません。"
	echo "-- [!実行不能] curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh を実行してください。"
	exit 1
else
	echo -n "-- Cargo OK => "
  echo $cargo_ver
fi

# pecoの確認と実行するファイルの選択
peco_ver=`peco --version`
if [ $? -ne 0 ]; then
  echo "-- peco Error"
  echo "-- [!実行不能] 「peco」が実行できませんでした。"
  echo "-- [!実行不能] 「peco」がインストールされていません。"
  echo "-- [!実行不能] brew install peco を実行してください。"
  exit 1
else
  echo -n "-- peco OK => "
  echo $peco_ver
  echo "-- "
  echo -e "-- (^_^)ノ \033[1;31m実行するファイルを選択してください。\033[0;39m"
  echo "-- "
  echo "-> 実行するファイル名を指定してください"
  echo "-> retuenキーで選択画面に進みます。"
  read Peco
  doFile=`ls -1 | grep "${FILE_NAME_PREF}" | peco`
fi

# ファイル名の加工
doFile=${doFile/${FILE_NAME_END}/}

# 実行
echo "-- Cargo Runを実行します。[${doFile}]"
echo "  "
cargo run --bin $doFile

# 終了処理
echo "  "
echo "----- FINISH ------"
echo "  "
echo "--==--==--==--==--==--==--==--==--==-- "

exit

以上

追記

作業中だけど、お出かけ中に電車の中とかで振り返りできるようにリポジトリ作ったのを公開します。
もしよければ、クローンしてご自由に使ってください。

https://github.com/neuvecom/my_rust_sandbox

使い方

  • クローンしたいディレクトリに移動
  • git clone https://github.com/neuvecom/my_rust_sandbox.git
  • cd my_rust_sandbox
  • zsh run.sh
    • MacOSのターミナルで使用する想定です
      • src/binにある、knock100_xxx.rsという形式のファイルを選択して実行できます。
      • Rustやその他必要なツールがない場合、インストール方法が提示されるので従ってくださtい。

追記2

54番目の課題(最大最小)でファイルの読み込みをする必要があったので、run.shを対応させる

  • 実行するファイルに、knock100_054を指定した時だけ、追加で、src/bim/054dataの中のファイルも指定するように変更(今後、ファイル指定の課題が増えるようなら、別途考えるけど、いまは個別対応で済ます)

The bookの後半にある、ファイルや環境変数の読み込みのところをつまみ読みしながらノック中。The book、基礎的なところで、文法の羅列みたいな部分に入って、100本ノックに逃げてきたけど、後ろの方チラ見したら、最終的にマルチスレッドのWebサーバーとか作ってるので、ちょっと楽しみになってきた。
つらい文法の章も乗り切れそうな気がしてきた。

あと、入力する部分のコードが毎回同じになるので、モジュール化して別ファイルで管理して共有して使えるように…的なカタチに改修。この記事が参考になった。

https://zenn.dev/newgyu/articles/3b4677b4086768

あとあと、コメントが //しか使えないみたいなのをどこかで読んで鵜呑みにしてたんだけど、普通に/* */も使えて複数行のコメントで使えるので、そちらに変更。

というわけで、なかなか進まないけど、環境が整ってきて、作業量/成果比率ではだいぶいい感じになっていると思うので、粛々と進めています。他の言語の応用でサクっといけちゃうよ? みたいな意見も見かけるけど、自分の感覚としては、考え方みたいなところがすごく違ってるので、面を喰らうんだけど、動かしてみてエラー読んで、視界がクリアになってくると、なるほどですねーってなる。
今までシェルやRubyでやってたやつ、順次置き換えて行けるようになるといいなぁ。

追記3

グラフィックス編にはいったところで、ツールがなくて頓挫しました。
なにか使えるものないかな…って探したら、Nannouというのが良さげです。でもって、使う前に英語のガイドを翻訳して読みますか…ってことになって、mdbookというrusu製のツール使ってるらしくて、mdbookが気に入って、そっちで書き直すことにしました。

途中経過ですが、こんな感じ。

https://super-care.surge.sh/

ちょっとずつやっていこうかと思います。

Discussion