読者です 読者をやめる 読者になる 読者になる

Rust入門 - 変数宣言と関数定義

Rustは強い静的型付け言語なので、関数定義もそれを意識しておこなう必要があります。

関数定義の前に、まずは変数宣言から見てみましょう。Rustは型推論してくれるので、以下のように型を付けなくてもエラーにはなりません。が、やっぱり明示的に型を指定したいところ。

というわけで厳密に書くとなると、以下のようになるわけですが最初はなかなか慣れないと思います。

let foo: i32 = 100;

let 変数名: 型 = 値; という意味。数値型の場合は符号付きか否か、何ビットかでそれぞれ型名が異なってきます。ここでのi32は、符号付き32ビット、のこと。

C系など、静的型付け言語を普段から書いている人ならなんてことはないですが、Web系言語では意識することがあまりなかったりするのでちょっと取っ付きにくいかもです。

関数定義も似たような感じになります。与えられた数値に100を加えて返す関数を書いてみます。

fn add_hundred(foo: i32) -> i32 {
    foo + 100
}

見た目が少しアレですが、こういうもんだ、ということにしておきます。

引数がある場合、変数宣言のように型を省略するとコンパイルエラーになってしまうので注意です。なるほど、確かに引数は型推論ではなくて明示的に決めたいよね。でないと、関数内で意図しないバグが大量発生することがあるので。

他でもよく見られるように値を返すときはreturnが使えますが、Rust的には非推奨だそうです。なぜか、についてまとめてみます。

Rust推奨の書き方は、上の例のようにアロー演算子みたいに書くようです。何を渡して何が返ってくるかが一目瞭然ですね、これ好き。

さて、中身を見て気付くかと思われますが、セミコロンがないですね。セミコロンを付けなくてもいい、ではなく、セミコロンを付けたらダメ、なのです。試しにセミコロンを付けてコンパイルするとエラーになります。

error: not all control paths return a value
fn add_hundred(x: i32) -> i32 {
    x + 100;
}

help: consider removing this semicolon:
    x + 100;
           ^

ここからわかるのは、Rustが文ではなく式ベース言語であるということと、セミコロンの意味が他言語とちょっと異なるということです。なるほどわからん。

式と文についておさらい。式は値を返すもの、文はそうでないもの、ですよね。Cの勉強をしていると、式の末尾にセミコロンを付けたものが文である、なんて説明をよく見かけますが…まぁいいや。

上の例の関数は返り値をi32の型と定義しています。しかしこれにセミコロンを付けてしまうと、i32ではなく空を返そうとするわけです。Rustはそこを察知し、なんか違う!とコンパイルエラーを出してくれるみたい。

ここでreturnの話に戻ると、returnはもちろん文になるのでセミコロンを付ければ正しく値を返せますが、式ベースのRustとしてはちょっと違くね?ということで非推奨みたいです。わかったような、わからないような。

兎にも角にも、Rustが非推奨しているなら使わないほうがいいです。今は非推奨でも将来的には仕様自体が消え去ることだってあるのだし。もちろん逆もあるけども。

ということで、以下のようになりました。

use std::io;

fn main() {
    // 関数へのポインタは普通に代入演算子でいけます
    let f = add_hundred;
    // ちなみに省略せずに書くと
    // let f: fn(i32) -> i32 = add_hundred;

    let x = f(100);
    println!("the value is: {}", x);
}

fn add_hundred(foo: i32) -> i32 {
    foo + 100
}

Rust入門 - 開発環境構築

我らが敬愛するMozillaによって開発中のRust、そのバージョン1.10.0がリリースされました。RustのRustによるRustな言語になったわけです(ぇ Rustの言語仕様だとかミッションポリシー的なことはググればいろいろ出てくるのでここでは割愛します。が、簡単に言うと安全なC++(異論は認める)という感じです。システムレベルの低層プログラ厶をゴリゴリ書けます。

開発環境構築からHello Worldまでの手順をまとめてみました。

インストールは超簡単。公式通りにやります。

% curl https://sh.rustup.rs -sSf | sh
% rustc --version
% export PATH="$HOME/.cargo/bin:$PATH"

さて、これでコーディングしてコンパイルして実行、までできるようになりました。が、当然のようにVimで開発するわけでして、シンタックスハイライトと補完くらいはできたらいいよね、ということでプラギンを入れていきましょう。今回はrust-lang/rust.vimracer-rust/vim-racerの2つを入れます。

ただ、単純にプラギンを入れればおkではなく、今回使わせてもらうプラギンにはRustのライブラリが別途必要になります。となるとパッケージマネージャーなどが欲しくなりますよね。ご安心ください。Rustインストール時にCargoというパッケージマネージャーがついてくるので、これを使えば問題ないです。cargoコマンドで普通にインストールしていきます。インストール後にパスを通しておくのを忘れずに。

% cargo install racer
% rustup component add rust-src
% export RUST_SRC_PATH="$HOME/.multirust/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src"
% cargo install rustfmt

RUST_SRC_PATHはvim-racerで使います。環境によってパスは異なるので注意。

ライブラリのインストールが終われば、あとはいつものように.vimrcでバンドルして、コンフィグをちょろっと書くだけ。以下は参考に。

let g:rustfmt_autosave = 1
let g:rustfmt_command = $HOME . '/.cargo/bin/rustfmt'

set hidden
let g:racer_cmd = $HOME . '/.cargo/bin/racer'

これで準備はおしまい。一先ずHello Worldしましょう。Rustの拡張子はrsなので、ブロジェクトディレクトリ下にsrcディレクトリを作り、main.rsなどとして作ってみることにします。ファイル名はhello_world.rsとかでも大丈夫ですが、アンダーバー記法推奨です。

% mkdir -p project/rust/hello_world/src
% cd project/rust/hello_world
% vim src/main.rs
fn main() {
    println!("Hello, world!");
}

見ての通りですが、どことなくCっぽい。うんうん、システムプログラミングはこうだよね(ぇ

main.rsをrustcコマンドでコンパイルすれば実行ファイルが出力されます、が、これは一旦忘れて別の方法でコンパイルします。そこで使うのが、パッケージマネージャーでもありビルドツールでもある先程のCargoになります。上記ライブラリのインストールに結構時間がかかったと思いますが、それはライブラリをコンパイルしていたからだったんですね。

Cargoでコンパイルするときは、コンフィグファイルを用意します。ファイル名はCargo.tomlです、Cは大文字。どことなくiniファイルに似ている。このコンフィグファイルには依存ライブラリ等も記述できます。なので、GitHubからクローンしたプロジェクトなどにローカルインストールしていないライブラリがあったとしても、build時にそれらも一緒にコンパイルしてくれるようになります。npm install的な、あんな感じです。そこらの話はまた別の機会に。

% vim Cargo.toml
[package]

name = "hello_world"
version = "0.0.1"
authors = [ "hoge piyo <hoge@piyo.com>" ]

コンフィグファイルができたら、buildを叩く。

% cargo build

buildが終わったら./target/debug下に出力されています。ちなみにreleaseオプションをつけることで最適化してくれます。あとは通常通り、実行ファイルを叩けば標準出力にHello Worldされます。が、ここではcargoを使って実行してみようと思います。

% cargo run

runはbuildと実行を一発でやってくれる便利コマンドで、rebuildが必要なときはbuildして実行、必要ないときは純粋に実行だけしてくれるのです。runでrebuildもしてくれるからといって、何でもかんでもrunで走らせるのはアレなので、build→runの手順を順守する癖を付けといたほうがいいかもです(別にRustだけに限った話ではないのだけども)

ちなみにcargoでtomlファイル含めてディレクトリもいろいろサンプルを自動生成してくれます。

cargo new hello_world --bin

とりあえずここまで。ハマるポイントは特にないですね。

2017/03/20 追記

バージョン1.16用に修正

レスポンシブWebデザインな仕事をしたときの話

セミ兄貴おっすおっすな時期になりました。あっついね。

では本文。Web開発ド素人の私(今まで仕事はVB.NETやCな業務アプリケーションばかり)が、レスポンシブWebデザインなサイト開発をした上で感じたことをとことこと書いていこうと思います。

レスポンシブWebデザイン、というのはデバイス毎にHTMLやらのソースを用意するのではなく、1つのソースで全デバイスにUIを提供する、みたいなことです。はてなのトップページとかがそんな感じです。PCのブラウザで開いて、画面幅を小さくしたり大きくしたりしてみましょう。小さくするとスマホで見る時のデザインに、大きくするとPCで見る時のデザインに、動的に変化している様子が見れると思います。有名なところだと、AppleとかAdobeとかAWSとか、割といろんなWebサイトが気付かないうちにレスポンシブWebデザインになっています。

そんなお話。

まず先に結論を。

レスポンシブWebデザインで嬉しい思いをするのはGoogle先生とエンジニアだけ(ぉ

順を追って説明していきましょう。

Googleによるモバイルサイト実装方法は、レスポンシブWebデザイン動的な配信別々のURL、という3つに分類されているようです。ちなみに、既存プロジェクトでは2番目の「動的な配信」がメインでした。UA判定してデバイス毎にテンプレートを切り出す、というよくある実装です。

ここで明らかにしておきたいことは、この3つの内、どれがSEO的に効果があるのか、ですよね。正解は、どれも一緒らしいです。Googleの中の人、ジョン・ミューラー氏曰く、

「レスポンシブデザイン」「動的配信」「別々のURL」は、サイト管理者の判断で選んで問題ない。それらが混在していても問題ない

www.youtube.com

とのこと。モバイルフレンドリーであるならそこは開発者に任せるよ、検索結果でも差別しないよ、ということです。ではなぜGoogleはレスポンシブWebデザインを推奨するのか。それは、クロールするリソースを最小限に抑えられるから、みたいです。結局Googleの都合なのかー(ぇ

つまり、「動的な配信」で既に構築されているサイトであれば、無理してレスポンシブWebデザインにする必要もない、という話になります。SEO的にもユーザビリティ的にも今までと変わらないのであれば、「乗るしかない、このビッグウェーブに」などと言わなくてもいいみたいです。

となると、開発側が楽できるか否か、だけが判断材料になるのかなぁと思います。PCのテンプレートを修正して、同じようにスマホのテンプレートを修正して、といった流れは修正漏れしてくださいと言わんばかりのものです。純粋なレスポンシブWebデザインではソースが1つだけになるので、そういったミスを防げるようになります。

ただやはりデメリットは付き物。それをいくつか列挙してみましょう。

  1. 慣れていないと工数が若干増える
  2. カッチリとレイアウト調整しようとするとハマる
  3. 画面表示速度が低下する可能性がある(後述します)

レスポンシブWebデザインでいこう、という話が上がってきた時は1度足を止めて、本当に必要かどうかをしっかり話し合ったほうがいいと思われます。(会社では言えないけど、今回のプロジェクトはどうみても失敗だったかと)

以下は開発における単なる愚痴です。

完成したソースには重複している箇所が所々あります。たとえば、PCサイズで閲覧しているときはAのヘッダーで、スマホサイズのときはBのヘッダーで、という感じに物理的に切り替えてたりしています。自分で書いておいてなんですが、酷すぎて笑えないです…。上に述べた「PCのテンプレートを修正して、同じようにスマホのテンプレートを修正して」というのと同じですね。レスポンシブのメリットを消しちゃっています。まあ既存デザインを踏襲して、というのがあったために強引にやるしかなかったという…。

また、画像をPCとスマホで出し分けしているところが結構あります。そうなってくると、スマホでアクセスしているのに、バックグラウンドではPCの画像もロードしている、なんてことになっているので多いに無駄な処理が発生しています。

これらが積み重なって、ページ表示速度は大きく下がってしまっています。Googleの推奨は1秒以内、全く達していないというのが現状です。これでリリースしちゃっていいのか、いやダメだろ。まあ解決策はいろいろある(RESSだったり、Virtual DOMで構築したり)とは思いますが。あとあと、PCデザインしか渡されなくて、「スマホデザインは良い感じにそっちでやって」というのがキツかった。出戻りだらけで工数膨らみまくり、という。

終わってから言うのもアレですが、兎にも角にもなんだかなぁな仕事でした。おわり。