簡単なツール作成を通して各プログラミング言語を比較しつつ学ぶ

# お題
アプリ実行中だけ機能する簡易Key/Valueストアを各プログラミング言語で実装してみる。
（最近、サービス毎に異なるプログラミング言語で実装されている現場に行くことが多いので、使ったことないプログラミング言語にも、それなりに慣れておくため）

お題のツールとしては（もっと便利なものは山ほどあるし）正直なところ日常的に役に立つものとはとても言えないのだけど、（すぐに挫折しないように）ミニマムに始める（けど、少しずつ各プログラミング言語の機能を使っていけるし、要件を拡張していきやすい）には、これくらいがいいかなと。

ちなみに、各言語のバージョンは以下の通り。
現場で使うことはまだなさそうだけど、Rustも加えてもいいかも。
PHPやTypeScriptも考えたけど、コンソールアプリ用途で選定されるだろうか？と疑問に思ったので止めた。

- Ruby ... v2.5
- Golang ... v1.11
- Java ... v1.8
- Scala ... v2.11
- Kotlin ... v1.3
- Python ... v3.6

# 更新履歴
- 【2019/08/03】コメントにならってRubyプログラムを修正
- 【2019/08/03】コメントでPythonプログラムの事例をもらったので追加

# 対象読者
JavaやRubyなど１つくらいプログラミング言語をある程度さわっている人。
その中でも、教科書読んだりチュートリアルやったりだといまいち理解できないから、やっぱり何かしらのアプリを実際に作ってみようという人。

# 注釈
自分としても使ったことないプログラミング言語で実装したりすることから、まずは相当拙いレベルから”とにかく動くものを作る”ことから始めてみる。
（お題の規模だと１ソースファイルで事足りるので、オブジェクト指向言語でも汎用性を考慮してクラス分割などしない。使えそうだとしても関数型の書き方もしない。）
ので、各プログラミング言語を知っている人からすると「こうすべき！」「これはまずい！」といった言いたいことが山ほどあると思うのだけど、そこはグッと堪えてもらいたく。

# 試行Index
- 第１回：[簡単なツール作成を通して各プログラミング言語を比較しつつ学ぶ](https://qiita.com/sky0621/items/32c87aed41cb1c3c67ff)
- 第２回：[【改善編】簡単なツール作成を通してRubyを学ぶ](https://qiita.com/sky0621/items/5868b19934187571d0cd)
- 第３回：[【改善編】簡単なツール作成を通してPython3を学ぶ](https://qiita.com/sky0621/items/27c610e08391c7cc83ea)
- 第４回：[【改善編】簡単なツール作成を通してGolangを学ぶ](https://qiita.com/sky0621/items/cb14aa67ef327922c0a1)
- 第５回：[【改善編】簡単なツール作成を通してJavaを学ぶ](https://qiita.com/sky0621/items/f19f5191754f61a4d4c3)
- 第６回：[【改善編】簡単なツール作成を通してScalaを学ぶ](https://qiita.com/sky0621/items/a68ae8b64d4856d1a195)
- 第７回：[簡単なツール作成を通してRustを学ぶ](https://qiita.com/sky0621/items/86d9159bc1930618162c)
- 第８回：[【改善編】簡単なツール作成を通してRustを学ぶ](https://qiita.com/sky0621/items/a70cc7a9453795e0c9e9)

# 実装・動作確認端末
### # OS - Linux(Ubuntu)
```
$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID_LIKE=debian
```

# 実践

## 要件
アプリを起動すると、起動中だけキーバリュー形式でテキスト情報を保存する機能を持つコンソールアプリ。
以下のように振る舞う。

**※「$ 」付きの状態がコンソールでコマンドを叩くことを表す。(無しはアプリ実行中。)**
**※Unix思想を踏まえ、保存や削除などは正常終了時は何も表示しない。**

### アプリ起動
<pre>
$ book

</pre>

バイナリ化していたら「`book`」と叩いて起動する想定だけど、スクリプト言語のケースもあるし、実際のアプリ起動方法はまちまち。
例えばRubyなら「`$ ruby main.rb`」だし、Goなら「`$ go run main.go`」だし。

### アプリ終了
<pre>
end

$
</pre>

### ヘルプ
<pre>
help

  ★ここに、コマンドの一覧や使い方を表示する。★
</pre>

### 保存
<pre>
save key01 val01

</pre>

正常に保存できた時は何も出力しない。（UNIX Philosophy ?）

### 取得
<pre>
get key01

val01
</pre>

### 削除
<pre>
remove key01

</pre>

### 一覧表示
<pre>
list

"key","value"
"key01","val01"
"11111","22222"
"キー","バリュー"
</pre>

## ■Ruby

### 開発環境

#### # 言語バージョン
```
$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-gnu]
```

#### # IDE - RubyMine
```
RubyMine 2019.1.2
Build #RM-191.7141.58, built on May 14, 2019
```

### ソース全量（【2019/08/03】コメントにならって修正）

```ruby:[main.rb]
def usage()
  puts <<~EOB

    [usage]
    キーバリュー形式で文字列情報を管理するコマンドです。
    以下のサブコマンドが利用可能です。

    list   ... 保存済みの内容を一覧表示します。
    save   ... keyとvalueを渡して保存します。
    get    ... keyを渡してvalueを表示します。
    remove ... keyを渡してvalueを削除します。
    help   ... ヘルプ情報（当内容と同じ）を表示します。

  EOB
end

# -------------------------------------------------------------------
# ここからメイン処理
# -------------------------------------------------------------------

cmd_store = Hash.new

puts "Start!"

loop do
  # 改行コードが含まれるので削る。
  cmd, *args = gets.chomp.split /\s+/

  case cmd

  # アプリ終了判定
  when "end"
    puts "End!"
    exit

  # ヘルプ
  when "help"
    usage
    next

  # 保存
  when "save"
    if args.size == 2
      cmd_store[args[0]] = args[1]
    else
      usage
    end

  # 取得
  when "get"
    if args.size == 1
      puts cmd_store[args[0]]
    else
      usage
    end

  # 削除
  when "remove"
    if args.size == 1
      cmd_store.delete(args[0])
    else
      usage
    end

  # 一覧
  when "list"
    puts '"key","value"'
    cmd_store.each {|k, v| puts %("#{k}","#{v}")}

  end

end
```

1ファイルだから上に載せたのが全量だけど、一応、ソースは下記に置いている。
https://github.com/sky0621/book_rb/tree/v0.2.0

### 動作確認

#### アプリ起動　〜　ヘルプ表示(help)　〜　アプリ終了(end)

<pre>
$ ruby main.rb 
"Start!"
help

[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
以下のサブコマンドが利用可能です。

list   ... 保存済みの内容を一覧表示します。
save   ... keyとvalueを渡して保存します。
get    ... keyを渡してvalueを表示します。
remove ... keyを渡してvalueを削除します。
help   ... ヘルプ情報（当内容と同じ）を表示します。

end
End!
$ 
</pre>

#### アプリ起動　〜　１件追加(save)　〜　追加データ確認(get)　〜　アプリ終了(end)

<pre>
$ ruby main.rb 
"Start!"
save key01 val01
get key01
val01
end
End!
</pre>

#### アプリ起動　〜　１件追加(save)　〜　追加データ削除(remove)　〜　追加データ確認(get)　〜　アプリ終了(end)

<pre>
$ ruby main.rb 
"Start!"
save key01 val01
remove key01
get key01

end
End!
</pre>

#### アプリ起動　〜　３件追加(save)　〜　データ一覧確認(list)　〜　アプリ終了(end)

<pre>
$ ruby main.rb 
"Start!"
save key01 val01
save 11111 22222
save キー バリュー
list
"key","value"
"key01","val01"
"11111","22222"
"キー","バリュー"
end
End!
</pre>

## ■Go

### 開発環境

#### # 言語バージョン
```
$ go version
go version go1.11.4 linux/amd64
```

#### # IDE - Goland
```
GoLand 2019.2
Build #GO-192.5728.103, built on July 23, 2019
```

### ソース全量

```go:[main.go]
package main

import (
	"bufio"
	"log"
	"os"
	"strings"
)

func usage() {
	msg := `

[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
以下のサブコマンドが利用可能です。

list   ... 保存済みの内容を一覧表示します。
save   ... keyとvalueを渡して保存します。
get    ... keyを渡してvalueを表示します。
remove ... keyを渡してvalueを削除します。
help   ... ヘルプ情報（当内容と同じ）を表示します。

`
	println(msg)
}

// -------------------------------------------------------------------
// ここからメイン処理
// -------------------------------------------------------------------

var cmdStore = map[string]string{}

func main() {
	println("Start!")
	for {
		s := bufio.NewScanner(os.Stdin)
		for s.Scan() {

			// アプリ終了判定
			if s.Text() == "end" {
				println("End!")
				os.Exit(-1)
			}

			// ヘルプ
			if s.Text() == "help" {
				usage()
			}

			if s.Text() == "" {
				usage()
				continue
			}

			// 以降は、引数ありコマンドの処理
			cmds := strings.Split(s.Text(), " ")

			// 保存
			if cmds[0] == "save" {
				if len(cmds) != 3 {
					usage()
					continue
				}
				cmdStore[cmds[1]] = cmds[2]
			}

			// 取得
			if cmds[0] == "get" {
				if len(cmds) != 2 {
					usage()
					continue
				}
				println(cmdStore[cmds[1]])
			}

			// 削除
			if cmds[0] == "remove" {
				if len(cmds) != 2 {
					usage()
					continue
				}
				delete(cmdStore, cmds[1])
			}

			// 一覧
			if cmds[0] == "list" {
				println(`"key","value"`)
				for k, v := range cmdStore {
					println("\"" + k + "\",\"" + v + "\"")
				}
			}

		}
		if s.Err() != nil {
			log.Fatal(s.Err())
		}
	}
}
```

1ファイルだから上に載せたのが全量だけど、一応、ソースは下記に置いている。
https://github.com/sky0621/book_go/tree/v0.1.0

## ■Java

### 開発環境

#### # 言語バージョン
```
$ java -version
openjdk version "1.8.0_202"
OpenJDK Runtime Environment (build 1.8.0_202-20190206132807.buildslave.jdk8u-src-tar--b08)
OpenJDK GraalVM CE 1.0.0-rc14 (build 25.202-b08-jvmci-0.56, mixed mode)
```

#### # IDE - IntelliJ IDEA
```
IntelliJ IDEA 2019.2 (Ultimate Edition)
Build #IU-192.5728.98, built on July 23, 2019
```

### ソース全量

```java:[Main.java]
import java.util.*;

public class Main {
    private static void usage() {
        String msg = "\n" +
                "[usage]\n" +
                "キーバリュー形式で文字列情報を管理するコマンドです。\n" +
                "以下のサブコマンドが利用可能です。\n" +
                "\n" +
                "list   ... 保存済みの内容を一覧表示します。\n" +
                "save   ... keyとvalueを渡して保存します。\n" +
                "get    ... keyを渡してvalueを表示します。\n" +
                "remove ... keyを渡してvalueを削除します。\n" +
                "help   ... ヘルプ情報（当内容と同じ）を表示します。\n" +
                "\n";
        System.out.println(msg);
    }

    // -------------------------------------------------------------------
    // ここからメイン処理
    // -------------------------------------------------------------------

    private static Map<String, String> cmdStore = new HashMap<String, String>();

    public static void main(String... args) {
        System.out.println("Start!");
        while (true) {
            Scanner s = new Scanner(System.in);
            String cmd = s.nextLine();

            // アプリ終了判定
            if (cmd.equals("end")) {
                System.out.println("End!");
                System.exit(-1);
            }

            // ヘルプ
            if (cmd.equals("help")) {
                usage();
                continue;
            }

            if (cmd.equals("")) {
                usage();
                continue;
            }

            // 以降は、引数ありコマンドの処理
            String[] cmds = cmd.split(" ");

            // 保存
            if (cmds[0].equals("save")) {
                if (cmds.length != 3) {
                    usage();
                    continue;
                }
                cmdStore.put(cmds[1], cmds[2]);
            }

            // 取得
            if (cmds[0].equals("get")) {
                if (cmds.length != 2) {
                    usage();
                    continue;
                }
                System.out.println(cmdStore.get(cmds[1]));
            }

            // 削除
            if (cmds[0].equals("remove")) {
                if (cmds.length != 2) {
                    usage();
                    continue;
                }
                cmdStore.remove(cmds[1]);
            }

            // 一覧
            if (cmds[0].equals("list")) {
                System.out.println("\"key\",\"value\"");
                cmdStore.entrySet().stream().map(e -> "\"" + e.getKey() + "\",\"" + e.getValue() + "\"").forEach(System.out::println);
            }
        }
    }
}
```

1ファイルだから上に載せたのが全量だけど、一応、ソースは下記に置いている。
https://github.com/sky0621/book_java/tree/v0.1.0

## ■Scala

### 開発環境

#### # 言語バージョン
```
$ scala -version
Scala code runner version 2.11.12 -- Copyright 2002-2017, LAMP/EPFL
```

#### # IDE - IntelliJ IDEA
```
IntelliJ IDEA 2019.2 (Ultimate Edition)
Build #IU-192.5728.98, built on July 23, 2019
```

### ソース全量

```scala:[Main.scala]
object Main extends App {
  def usage(): Unit = println(
    """
      |[usage]
      |キーバリュー形式で文字列情報を管理するコマンドです。
      |以下のサブコマンドが利用可能です。
      |
      |list   ... 保存済みの内容を一覧表示します。
      |save   ... keyとvalueを渡して保存します。
      |get    ... keyを渡してvalueを表示します。
      |remove ... keyを渡してvalueを削除します。
      |help   ... ヘルプ情報（当内容と同じ）を表示します。
      |
      |""".stripMargin)

  // -------------------------------------------------------------------
  // ここからメイン処理
  // -------------------------------------------------------------------

  import scala.collection.mutable

  var cmdStore = mutable.Map.empty[String, String]

  println("Start!")
  while (true) {
    val cmds = io.StdIn.readLine().split(" ")

    // アプリ終了判定
    if (cmds(0) == "end") {
      println("End!")
      sys.exit(-1)
    }

    // ヘルプ
    if (cmds(0) == "help") {
      usage()
    }

    if (cmds(0) == "") {
      usage()
    }

    // 保存
    if (cmds(0) == "save") {
      if (cmds.size != 3) {
        usage()
      } else {
        cmdStore += (cmds(1) -> cmds(2))
      }
    }

    // 取得
    if (cmds(0) == "get") {
      if (cmds.size != 2) {
        usage()
      } else {
        if (cmdStore.contains(cmds(1))) {
          println(cmdStore(cmds(1)))
        }
      }
    }

    // 削除
    if (cmds(0) == "remove") {
      if (cmds.size != 2) {
        usage()
      } else {
        cmdStore -= cmds(1)
      }
    }

    // 一覧
    if (cmds(0) == "list") {
      println("\"key\",\"value\"")
      for ((k, v) <- cmdStore) println("\"%s\",\"%s\"".format(k, v))
    }
  }
}
```

1ファイルだから上に載せたのが全量だけど、一応、ソースは下記に置いている。
https://github.com/sky0621/book_scala/tree/v0.1.0

## ■Kotlin

### 開発環境

#### # 言語バージョン
```
v1.3
```

#### # IDE - IntelliJ IDEA
```
IntelliJ IDEA 2019.2 (Ultimate Edition)
Build #IU-192.5728.98, built on July 23, 2019
```

### ソース全量

```kotlin
import java.util.*
import kotlin.system.exitProcess

fun usage() {
    val msg = """

[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
以下のサブコマンドが利用可能です。

list   ... 保存済みの内容を一覧表示します。
save   ... keyとvalueを渡して保存します。
get    ... keyを渡してvalueを表示します。
remove ... keyを渡してvalueを削除します。
help   ... ヘルプ情報（当内容と同じ）を表示します。

        """.trimIndent()
    println(msg)
}

// -------------------------------------------------------------------
// ここからメイン処理
// -------------------------------------------------------------------

var cmdStore = mutableMapOf<String, String>()

fun main(vararg args: String) {
    println("Start!")
    while (true) {
        val s = Scanner(System.`in`)
        val cmd = s.nextLine()

        // アプリ終了判定
        if (cmd == "end") {
            println("End!")
            exitProcess(-1)
        }

        // ヘルプ
        if (cmd == "help") {
            usage()
            continue
        }

        if (cmd == "") {
            usage()
            continue
        }

        // 以降は、引数ありコマンドの処理
        val cmds = cmd.split(" ")

        // 保存
        if (cmds[0] == "save") {
            if (cmds.size != 3) {
                usage()
                continue
            }
            cmdStore[cmds[1]] = cmds[2]
        }

        // 取得
        if (cmds[0] == "get") {
            if (cmds.size != 2) {
                usage()
                continue
            }
            println(cmdStore[cmds[1]])
        }

        // 削除
        if (cmds[0] == "remove") {
            if (cmds.size != 2) {
                usage()
                continue
            }
            cmdStore.remove(cmds[1])
        }

        // 一覧
        if (cmds[0] == "list") {
            println("\"key\",\"value\"")
            cmdStore.forEach { k, v -> println("\"$k\",\"$v\"") }
        }
    }
}
```

1ファイルだから上に載せたのが全量だけど、一応、ソースは下記に置いている。
https://github.com/sky0621/book_kt/tree/v0.1.0

## ■Python

### 開発環境

#### # 言語バージョン
```
$ python3 --version
Python 3.6.8
```

#### # IDE - PyCharm
```
PyCharm 2019.2 (Professional Edition)
Build #PY-192.5728.105, built on July 24, 2019
```

### ソース全量

```python:[main.py]
def usage():
    msg = """
[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
以下のサブコマンドが利用可能です。

list   ... 保存済みの内容を一覧表示します。
save   ... keyとvalueを渡して保存します。
get    ... keyを渡してvalueを表示します。
remove ... keyを渡してvalueを削除します。
help   ... ヘルプ情報（当内容と同じ）を表示します。

"""
    print(msg)


# -------------------------------------------------------------------
# ここからメイン処理
# -------------------------------------------------------------------

cmd_store = {}

print("Start!")
while True:
    cmd = input()

    # アプリ終了判定
    if cmd == "end":
        print("End!")
        exit()

    # ヘルプ
    if cmd == "help":
        usage()
        continue

    # 以降は、引数ありコマンドの処理
    cmds = cmd.split()
    if len(cmds) < 1:
        usage()
        continue

    # 保存
    if cmds[0] == "save":
        if len(cmds) != 3:
            usage()
            continue
        cmd_store[cmds[1]] = cmds[2]

    # 取得
    if cmds[0] == "get":
        if len(cmds) != 2:
            usage()
            continue
        print(cmd_store[cmds[1]])

    # 削除
    if cmds[0] == "remove":
        if len(cmds) != 2:
            usage()
            continue
        del cmd_store[cmds[1]]

    # 一覧
    if cmds[0] == "list":
        print('"key","value"')
        for k, v in cmd_store.items():
            print(f'"{k}","{v}"')
```

1ファイルだから上に載せたのが全量だけど、一応、ソースは下記に置いている。
https://github.com/sky0621/book_py/tree/v0.1.0

# 解説
この規模なら、何かしらのプログラミング言語でコンソールアプリ作ったことあればやってることは理解できそうな気はする。
なので、部分部分だけピックアップ。

## ◆ヒアドキュメント

モダンな言語では、書かれたままを文字列として表現できるヒアドキュメントが使える。
残念ながらJavaには無いので、文字列の＋結合で似た形に寄せる。

### Ruby
```ruby
def usage()
  puts <<~EOB

    [usage]
    キーバリュー形式で文字列情報を管理するコマンドです。
　　　　〜〜〜
    help   ... ヘルプ情報（当内容と同じ）を表示します。

  EOB
```

### Golang
```go
func usage() {
	msg := `

[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
　〜〜〜
help   ... ヘルプ情報（当内容と同じ）を表示します。

`
	println(msg)
}
```

### Java
```java
    private static void usage() {
        String msg = "\n" +
                "[usage]\n" +
                "キーバリュー形式で文字列情報を管理するコマンドです。\n" +
                  〜〜〜
                "help   ... ヘルプ情報（当内容と同じ）を表示します。\n" +
                "\n";
        System.out.println(msg);
    }
```

### Scala
```scala
  def usage(): Unit = println(
    """
      |[usage]
      |キーバリュー形式で文字列情報を管理するコマンドです。
　　　　　〜〜〜
      |help   ... ヘルプ情報（当内容と同じ）を表示します。
      |
      |""".stripMargin)
```

### Kotlin
```kotlin
fun usage() {
    val msg = """

[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
　〜〜〜
help   ... ヘルプ情報（当内容と同じ）を表示します。

        """.trimIndent()
    println(msg)
}
```

### Python
```python
    msg = """
[usage]
キーバリュー形式で文字列情報を管理するコマンドです。
　〜〜〜
help   ... ヘルプ情報（当内容と同じ）を表示します。

"""
    print(msg)
```

## ◆ハッシュマップ生成

Rubyは全てがオブジェクト。`new`キーワードを使う。
ただ、Javaでは「`new HashMap()`」となるが、Rubyでは「`Hash.new`」となる。
そして型は明示化しなくてよい。（JavaもVer.10で型推論が導入されたけど）
対して、Golangではマップは特殊な構文。

### Ruby
```ruby
cmd_store = Hash.new
```

### Golang
```go
var cmdStore = map[string]string{}
```

### Java
```java
private static Map<String, String> cmdStore = new HashMap<String, String>();
```

### Scala
```scala
import scala.collection.mutable
var cmdStore = mutable.Map.empty[String, String]
```

### Kotlin
```kotlin
var cmdStore = mutableMapOf<String, String>()
```

### Python
```python
cmd_store = {}
```

## ◆無限ループ

処理待ち受けアプリでおなじみにの無限ループ。
他の言語だと「`while true`」を使うことが多いけど、Rubyには（「`while true`」も使えるけど）上記の書き方で実現できる。
Golangはとにかく言語自体をシンプルにしているので「`for`」で無限ループも賄う。

### Ruby
```ruby
  loop do
　　〜〜〜　ここの処理が（明示的に終了しない限り）無限ループ　〜〜〜
  end
```

### Golang
```go
  for {
　　〜〜〜　ここの処理が（明示的に終了しない限り）無限ループ　〜〜〜
  }
```

### Java
```java
  while (true) {
　　〜〜〜　ここの処理が（明示的に終了しない限り）無限ループ　〜〜〜
  }
```

### Scala
```scala
  while (true) {
　　〜〜〜　ここの処理が（明示的に終了しない限り）無限ループ　〜〜〜
  }
```

### Kotlin
```kotlin
  while (true) {
　　〜〜〜　ここの処理が（明示的に終了しない限り）無限ループ　〜〜〜
  }
```

### Python
```python
while True:
　　〜〜〜　ここの処理が（明示的に終了しない限り）無限ループ　〜〜〜
```

## ◆標準入力

要件として、アプリ起動後は標準入力を待ち受ける状態となる。

### Ruby

これを実現するのが「`gets`」。これ書くだけで、この行でユーザからの入力を待ち受ける状態になる。
ちなみに、「`chomp`」は標準入力から改行コードを除去するコード。

```ruby
  cmd, *args = gets.chomp.split /\s+/
```

### Golang

OSからの標準入力を`Scanner`を用いて取得。

```go
    s := bufio.NewScanner(os.Stdin)
    for s.Scan() {
      〜〜〜
      cmds := strings.Split(s.Text(), " ")
      〜〜〜
    }
```

### Java

Javaも`Scanner`を使う。

```java
    Scanner s = new Scanner(System.in);
    String cmd = s.nextLine();
      〜〜〜
    // 以降は、引数ありコマンドの処理
    String[] cmds = cmd.split(" ");
```

### Scala

```scala
    val cmds = io.StdIn.readLine().split(" ")
```

### Kotlin

```kotlin
    val s = Scanner(System.`in`)
    val cmd = s.nextLine()
      〜〜〜
    // 以降は、引数ありコマンドの処理
    val cmds = cmd.split(" ")
```

### Python

```python
    cmd = input()
```

## ◆アプリ終了

### Ruby
```ruby
      exit
```

### Java
```java
      System.exit(-1);
```

### Scala
```scala
      sys.exit(-1)
```

### Kotlin
```kotlin
      exitProcess(-1)
```

### Python
```python
        exit()
```

## ◆コレクション走査

言語によって特色の出やすいコレクション走査。
Rubyでは「`each`」で各々の要素を操作する処理を明示し、「`|k, v|`」という書き方で１件毎のキーとバリューを参照する。
Golangではコレクションは`range`で走査。
Javaでコレクションといったら`stream`が登場。ただ、他の言語より書きっぷりが冗長？

### Ruby
```ruby
    cmd_store.each {|k, v| puts %("#{k}","#{v}")}
```

### Golang
```go
      for k, v := range cmdStore {
        println("\"" + k + "\",\"" + v + "\"")
      }
```

### Java
```java
      cmdStore.entrySet().stream().map(e -> "\"" + e.getKey() + "\",\"" + e.getValue() + "\"").forEach(System.out::println);
```

### Scala
```scala
      for ((k, v) <- cmdStore) println("\"%s\",\"%s\"".format(k, v))
```

### Kotlin
```kotlin
      cmdStore.forEach { k, v -> println("\"$k\",\"$v\"") }
```

### Python
```python
        for k, v in cmd_store.items():
            print(f'"{k}","{v}"')
```

# まとめ
簡単なツールレベル、かつ、言語特有の強みが出る書き方でなく、どれも似たような書きっぷりになるよう意識してしまった結果、構文としての多少の差異ぐらいしか見えなくなってしまった・・・。
言語の強みがちゃんと出るように書くようにしないと、お題を満たすものにはならないか・・・。

今回みたいな事例だとわかりづらいけど、例えばDBアクセスを伴う（いわゆる）Webシステムを（シビアなパフォーマンス要件はなく）早く作りたいとなると、`Ruby` + `Ruby on Rails`の組み合わせは強いんじゃないかと思う。
（自分は仕事で一からこの組み合わせで作ったことはなく、あくまでチュートリアルレベルをやった上での感想）
`Golang`は、（現場のエンジニアがGoしか使えないとかなければ）Webシステムを作るのに使おうと思った時の必然性には乏しいと個人的には思う。
逆に、マシンリソースを効率よく使ってパフォーマンスを上げたいといった時や、こじんまりとした（でもWindowsでもMacでもバイナリ１つで動く）開発補助ツールを作りたいといった時に、`Golang`は適していると思う。
（自分は家でも仕事でも実際に上記のようなケースで`Golang`を使った上での感想）
`Java`並びに`Scala`、`Kotlin`といったJVM系言語は、個人で何か小さくアプリ作成を始める場合には他により適した言語がありそうだけど、なんといっても、どんなアプリ、システムを作るにしてもそれなりに使いやすい汎用性の高さと、豊富な既存資産が活かせるといった強力な強みがあると思う。
（まあ、既存資産は捉え方によっては弱みとも言えるけど・・・）

以上、お題とも離れ、まとめにもならないまとめ。（余裕が出たら、次はWebシステム作成を通しての比較記事かなぁ。）