見出し画像

Retro-gaming and so on

Rustを触ってみた

ここで色々書いたんだけど・・・・・・。
急に思い立って、Rustを取り敢えず試してみることにした。

これを今まで一回も触ったことがない、ってのは理由があるんだ。
Ubuntu(※1)なんかのLinuxディストリビューションの場合、通常、「何かプログラミング言語を試したい」と言った場合、ディストリビューションが公式に提供しているリポジトリ(ソフトウェアを揃えてるサーバー)からその言語と関連ツールが一式纏めてダウンロード/インストールできる。
Windowsのように「公式サイトを訪れてダウンロードページへ行き、ダウンロードボタンをクリックして、ダウンロードして、インストーラをクリックして待つことx秒」とかやんなくて良いんだ。
ぶっちゃけ、この「リポジトリ」というシステムがWindowsというOSと決定的に違うLinuxディストリビューションの旨味なんだよな。ネット上検索しまくってダウンロードされるブツを通常探さなくて良い。何故なら一括管理されてるから、だ。
ところが、現時点、RustはUbuntuレポジトリから提供されていない。「えええ、レポジトリに入ってないなんて・・・」と、通常、Windowsではフツーの、ブラウザでダウンロードサイトを訪ねて・・・というプロセスを考えただけ、で億劫になってたのだ(笑)。
だからアレだよ、人間って「ラクな環境に慣れると」そこからハズレた行動をするのを凄く億劫に感じるもんなんだって(笑)。いや、マジで。
そんなのもあって、以前、人にも薦められたこたぁあったんだけど、Rustを触るのを避けていたのだ。もう、フツーにダウンロードしてインストールするのがメンド臭かったから。それが最大の理由である(笑)。


Ubuntuに付属してるソフトウェアダウンロード/インストール用のSynaptic パッケージマネージャー。これでネットを駆けずり回ることなく、欲しいソフトをUbuntuの公式アーカイブから取ってくることができる。

んで、今回、フツーにRustをダウンロード/インストールしてみた。Linuxではcurlというコマンドでダウンロード/インストールするが、実のトコ、これは原理的には「目的のWebページを訪ねてダウンロードボタンをマウスでクリックする」ってのと変わらない。コマンドラインだとその辺全く同じことをやってても、端末でワンライナー記述出来てる、ってことなだけである。
Rustは結構デカいシステムみたいで、C言語的なコンパイラ(rustc)を使った従来通りの地味なプログラミングも可能なんだけど、rustup(rustで提供されているシステムを一括アップデートする)というツールやcargoと言った統合開発システムが付随していて、特に開発時ではcargoが中心となってる模様だ。
SpacemacsにもRust contribution layer for Spacemacsというレイヤーが提供されていて、IDEとして働いてくれる。
唯一最初ハマったのは、SpacemacsでRust用の自動補完機能が働かなかったことだ。
元々、Emacsでは、各言語用のプラグインをEmacs Lispで書いて・・・というのがスタイルだったんだが、ここ10年ちょっとくらいでは、Rustのようにプログラミング言語処理系自体が何らかのシステムを提供しているケースが増えてきている。従って、Emacs側からそれらを呼び出して・・・とスタイルが変わってきてるわけだが、結果としてプログラミング言語本体側の設定をどーにかせんと、Emacs側からコントロールできない、という事象をちょくちょく見かけるようになってきている。
で、結論からいうと、Spacemacsで自動補完機能を正常に動かす為には、Rust側での環境設定の為のコマンドを一回走らせなアカン、ということである。

rustup update
rustup toolchain add nightly
rustup component add rust-src

この3つをコマンドライン(WindowsならDOS窓/PowerShell、Linuxならshell)で走らせれば、無事、自動補完用の某が、環境変数に登録されて、Spacemacsからアクセスが可能となる。



Rustのcargoはgitを利用していて、ディレクトリをデフォルトとして色々と作成しつつそれらをソースレポジトリとして管理するようになっている。
ということは、C言語やLispのように、素朴に自分で何でも管理するスタイルに慣れているとかなり面食らうだろう。Rustのcargoは即「開発」できるようなシステムを提供している。言わばIDEの機能の半分くらいをRust自体が奪ってるようなシステムになってんだな。
まぁ、モダンなシステムとしては、素のままでも色々と「管理」してくれて手とり足とり、の方がラクたぁ言えるだろう。

さて、言語そのものに付いて。
まずは有名なHello Worldプログラムを見てみよう。Rustでは次のように書く。

fn main() {
    println!("Hello, world!");
}

これは見た目から言うと確かにC言語とそっくりである。

#include <stdio.h>
#include <stdlib.h>

int main(void) {
  print("Hello, world!");
  return EXIT_SUCCESS;
}

Cの言語仕様上要求されている「書き方」と比べると要素数は減ってはいるが、確かに基本的な見た目はC言語のそれを模してはいる。
ところが、Rustには大きな特徴がどうやら3つくらいある模様だ。

まず1つ目。型の宣言について、だが(RustはRacketやPythonと違って静的型付け言語だ)、これはC言語型ではなく、Pascal型を採用している。

fn main() {
 another_function(5);
}

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

C言語ならこう書くだろう。

#include <stdio.h>
#include <stdlib.h>

void another_function(int x);

int main(void) {
 another_function(5);
 return EXIT_SUCCESS;
}

void another_function(int x) {
 printf("The value of s is: %d", x);
}

注目して欲しいのは関数another_functionの引数である。C言語の場合は、int型のxを仮引数として要求するのに int x と型名を仮引数の前に置いてるが、Rustの場合は x: i32 と型名 i32 は仮引数xを後側から修飾している。これはPascalに見られる形式だ。

program Sample(output);

procedure another_function(x : integer);
begin writeln('The value of s is: ', x) end;

begin
 another_function(5);
end

Pascalでもintegerと言う型名は変数xを後方から修飾してる。
よく知らんのだが、実は型宣言の場合、Pascalのように「後方から修飾する」のがコンピュータサイエンス上は正しいらしい。何より、複数の変数を後方から一気に型宣言で修飾することが可能で、これはC言語では見られない特徴である。

// C言語ではこういう記法は便利そうだが許されない。

void another_function(int x, y, ...) { ...

(* 一方、Pascalではこういう記法が許される。 *)

procedure another_function(x, y, ... : integer); ...

つまり、Pascalの場合は、変数の型によって仮引数をグルーピングできるので型記述の手間がかからない。
一方、ぶっちゃけC言語はやっつけ仕事で作ったプログラミング言語なのでAlgolの仕様を受け継いでる、と言いながらこのテの設計ミスがある(いや、これはミスなんだ・※2)。
とは言ってもRustの場合、Pascalみたいに変数の型を後方から一気に修飾できる、と言うわけではないらしい(少なくともチュートリアルをザーッとみた結果、そういう記述は見つからんかった)。
と言うわけで、Rustでは記述はPascal方式、実質はC言語方式、と言えるだろう。

2つ目。C言語は破壊的変更をする、ってのがベースの言語だがRustはそうではない。
いや、破壊的変更が「出来ない」わけじゃないんだけど、変数にmutキーワードを付け足さないと破壊的変更が出来ない。
つまり、破壊的変更を目論む場合、記述コストが生じるような設計になっている。

let mut guess = String::new();

これは恐らく、Rustは並列処理を前提にしてるから、だろう。いずれにせよ、関数型プログラミング的には望ましいスタイルを、ベースとしては強制する形になっている。

3つ目。Rustはどういうわけか、Lispのような式指向の言語である、と言うこと。
C言語のセミコロン(;)は式の終わりを表す意味だった。
一方、Rustのセミコロン(;)はそういうことを意図してはいないようだ。実はこの辺がC言語と大きく違う。
Rustのセミコロン(;)の存在は、その式が「値を返さなくてもいいよ」と言うサインになってる模様だ。
よって、次のような記述が可能となっている。

fn main() {
 println!("{}", another_function());
}

fn another_function() -> i32 { // ここで返り値が i32 型になることを宣言
 let x = 5;
 x // return がないが x が返り値になる
}

要するに、一応rustにはreturnもあることはあるが、一般にはセミコロンでそこがreturnなのかそうじゃないのか判別してる、と言うことだ。明示的な return が存在しないSchemeとかRubyに近い、と言えるだろう。
もっとRustの恐ろしいことは、いわゆるif文と言われるものの結果を直接変数に代入出来てしまう辺りだ。

fn main() {
 let flag = true;
 let x = if flag {
  "hoge"
 } else {
  "fuga"};
 println!("{}", x);
}

いや、「恐ろしいことに」と書いたが、これはLispならフツーだ。Lisp使いならこんなコードは山ほど書いたことがあるだろう。

;; Racket での例
(define (main)
 (let* ((flag #t)
   (x (if flag
     "hoge"
     "else")))
  (display x)
  (newline)))

要するに、Rustのifは文じゃない。Lispと同じように式、なんだ。
似たようなことは、C言語だと三項演算子の力を借りないと出来なかったが、Rustは素のままで行うことができる。
これは恐ろしい進歩である。

とまぁ、ザーッとRustを見てみた。
感想で言うと、RustはC言語の皮を被った関数型言語と言う印象である。あるいはもっと具体的に言うとC言語の皮を被ったHaskellとかC言語の皮を被ったOCamlって印象かな。一見、C言語型の構文を用いてるけど、その実態はかなりモダンな言語である(※3)。
これで一体どのように低レベル操作を目論んでるのか、なかなか謎は尽きない、ってのが正直なトコだ。
でも、これからプログラミングをはじめたい、しかもC言語みたいに低レベル操作を行いたい、って要望がある人には絶好のプログラミング言語のチョイスとなる、ってのは間違いないだろう。

Stack Overflowのようなハッカーが集まる場所で、もっとも愛されてるプログラミング言語の第一位になってるのも分かる気がする。C言語もPythonもおさえて1位なのだ。この意味が分かるだろうか。
これから低レベルなプログラミングをやってみたい、と言う人はC言語を考慮する前にRustを考慮すべきだろう。
それが21世紀の選択になるのかもしれないのだ。

※1: ちなみに、僕が使用してるのはXubuntuという派生バージョンだ。
※2: 実際、C言語を最初に作ったデニス・リッチーは「あれは失敗だった」と述懐してるらしい。
C言語自体は、実のことを言うと、これ自体を「速攻で組み立てなければならなかった」為、色々とどう考えても不格好なデザインがあったのである。
※3: 例によって、C言語脳には「あれ?」って言うような機能山盛り、に見えるだろうが、関数型言語経験者には割に「分かりやすい」機能や概念がてんこ盛り、と言う印象になっている。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「プログラミング」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事