6月 18, 2018

Go言語は突然に(4日目)

Go言語のいいところ

子どもの頃から流行りモノにあまり興味がなくて、「こんなに凄いのに、こんなに面白いのになんで全然知られてないの?」みたいなモノばかり追いかけるのが好きでした。

唐突な人生語りで始まってしまいましたが、私がGo言語に惹かれてやまないのも、実はそういった側面があるからかもしれないと最近改めて気付いた次第です。なので、Go言語の良いところを書いて、少しでも多くの人々の目に触れること。そして、もし開発言語を選ぶときに選択肢のひとつとして上がってくれたら嬉しいなと思って記事を書いています

まだGo言語に触れたばかりの自分がそんなことをしていいものかと一瞬怯む気持ちもありました。しかし、Linuxの生みの親であるリーナス・トーバルズ氏のJUST FOR FUN(それがぼくには楽しかったから)という言葉がふわりと背中を押してくれました。自分にとって楽しいと思えることをやること。それが何よりもポテンシャルが出るし、場合によっては何かを変えることだってできる。なので気楽にやっていこう、そんな風に思えるようになってきました。

前フリが長くなってしまいましたが改めて、そんな訳で本連載はGo言語のいいところ、すごいところについて引き続き書いてゆきたいと思います。

新人くん、落とし穴に嵌る

現在私が携わっている業務のプロジェクトのチームには、3月に入社した新人くん(以下、Sくん)がいます。彼はプログラムを書くのはほぼ初めてという状態でしたが、一緒にJavaやGo言語でのプロジェクトをこなし、もともとの勘の良さもあり着々と実力を付けてきています。それでもプログラミングという一筋縄ではいかない作業の中、落とし穴に嵌り込むこともよくあります。今回嵌った落し穴はプログラミングという作業のややこしさを表す典型的な事例だと思ったので、本人承諾のもとご紹介してみたいと思います。

現在、開発しているシステムはGo言語を使用して作っています。Goの強力なWeb機能(apacheを使わず数行でサーバ処理が書ける!)を使ってバックエンドで処理した情報をWeb画面で参照できるようにしています。Sくんにお願いしたのは、サーバサイドで処理をした情報をテンプレート経由でフロント側(HTML、CSS、JavaScriptの世界)に持ってきて、あとは画面レイアウトにあわせて表示するだけというところ。サーバサイドでJSONや構造体を使った処理も書けるようになってきたので、そんな難しいところではないと思っていたのですが隣から「嵌っている感」がひしひしと伝わってきます。

うまく動かないというJavaScriptのプログラムを簡略化して表現すると、こんな感じになっていました。

[javascript title=”【誤ったプログラム】” collapse=”false”]
items = [‘狐’,’cat’,’ねずみ’]

for(var i = 0; i <= items.length; i++) {
item = items[i];
console.log(item)
}
[/javascript]

プログラムに馴染のある方は一目で「あっ!」と脳内で警報が鳴り響くかと思います。そうでない方のために以下で解説をしてゆきます。結論から言うと、この書き方だとfor分のループを1周余計に回ってしまい、そのことにより様々な不具合を誘発する原因となるのです。(※実際にはdomを操作していたので、存在しないオブジェクトを参照し落ちていました)

JavaScriptのfor文

せっかくの機会ですので、プログラムの解説をしてみたいと思います。このプログラムはこんなこと(処理)をしています。

・itemsという配列(複数の箱)には「狐、cat、ねずみ」という3つの言葉が入っています。

・for文は配列の要素(箱の中身)の数だけ繰り返し、要素(箱の中身)をひとつずつ取り出して表示します。

目的も実装も極めてシンプルなプログラムなのですが、ここに暗黙の前提があるのですね。

・配列itemsの何番目の要素かを示すインデックスは「0」から開始する。すなわち、items[0]が「狐」、items[1]が「cat」、items[2]が「ねずみ」を表します。

・「items.length」は要素の数を表すので、今回の場合は「3」となります。

・for文がループを続ける条件は「i <= items.length;」という部分が表しています。iという値(0から始まって、ループするたびに(i++で)1増える)が、items.length(3)以下(<=)の場合にループが継続されます。

このことを踏まえると、上記のプログラムは「iが0、1、2、3の場合の4回ループするけれど、itemsの要素は0から2の3つ」なので1回余計に回ってしまうということになります。しかも、items[3]は自分で作っていないので何が入っているかわからないし、こうした未定義の値を使うとエラーとなってしまうこともあります。

・・おわかりいただけたでしょうか。説明していて正直私自身が無力感を感じてしまったので、せめて理解の補足になればとちょと図を描いてみました。

 

そして、下記が正しいプログラムとなります。

[javascript title=”【正しいプログラム】” collapse=”false”]
items = [‘狐’,’cat’,’ねずみ’]

for(var i = 0; i < items.length; i++) {
item = items[i];
console.log(item)
}
[/javascript]

さきほどのプログラムとの違いは「<=(左辺が右辺以下)」が「<(左辺が右辺より小さい)」になっているだけです。たったこれだけで、ループの回数が正しい3回になり、items[3]という存在しないはずの謎の箱を開いてしまう危険がなくなりました。

こうした書き方は言語の差はあれど「インデックスが0から始まり、配列の要素がitems.lengthのように簡単に取れる」ことを前提とした、シンプルで美しいお約束・定石の書き方として流布しています。これがお約束で当たり前だから覚えなくてはいけない、それがプログラムというものだと思っていたのですが、今回のSくんの件を見てその考え方も少し変わってきました。

Go言語のfor文

というのも、SくんはGo言語では普通にループによる要素参照の処理を書いていたのです。さきほどの処理をGo言語で書くとこんな感じになります。(※厳密にはスライスなのですが、今回はそこの説明は省略します!)

[python title=”【Go言語の場合】” collapse=”false”]
items := []string{"狐", "cat", "ねずみ"}
for _, item := range items {
fmt.Println(item)
}
[/python]

JavaScriptのときよりもさらにシンプルになっています。具体的には、こんなところが改善されています。

・itemsの要素はitemという変数に自動的に入れてくれるので、for文内でいきなり使える。

・要素の数(length)もカウンタ兼インデックス(i)も使う必要がない。

さきほどの図を上のプログラムにあわせてみるとこんな感じでしょうか。

箱の何番目かというインデックスや箱の長さを意識しないでも、箱の中身を簡単に取り出せるようになっています。使いたくなったらどうするんだ?と疑問を持たれる方もご安心ください、必要であればすぐに使えます(ヒント:「_」)

もちろん、複雑な処理を書かなければならないときにはそれに応じた知識も必要となってくるのですが、よく使う処理が簡単に書けるようになればプログラミング自体のハードルが下がって、開発者の数が増えたり、その分他のことにリソースが回せるようになったりというメリットがあるのではないかと思います。プログラミング言語というのも進化してゆくのだなと思います。

次回予告

「でもこれって、Pythonも同じじゃね?」と思った方、はい、その通りです。でも、Go言語の良さはこんなものではございません次回、このブログにまた来てみてください。見せてあげますよ、本当のGo言語の魅力ってヤツを。と、既に若い人には通じるかどうか分からないネタでいったん締めたいと思います。それではまた!

最後までお読みいただき、誠にありがとうございます。


安藤篤志

  • facebook
  • twitter
  • line
  • このエントリーをはてなブックマークに追加

アットファイブで一緒に働きませんか?

エンジニアをはじめ、複数の職種で仲間を募集しています!