Go
golang
Immutable

Goで文字列を逆順にする方法とイミュータブルについて

サンプルコード

この記事を参考にしました

func reverse(s string) string {
    rs := []rune(s)
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        rs[i], rs[j] = rs[j], rs[i]
    }
    return string(rs)
}

GoってRubyみたいに"hoge".reverseで簡単に文字列を逆順にできないみたい。自前で関数実装するのはやや大変ですね。

以下余談

上記で出てくる runeについては以下が参考になります。

Go言語のstring型はイミュータブルなのでミュータブルなrune型にしないといけないです。そのため、上記のfunc reverseでは引数のstringをいったんrune型にしてるんですね

ミュータブル/イミュータブル?

ミュータブル(mutable)は英語で「可変」という意味です。mutableに否定を表す接頭語imをつけることでイミュータブル(immutable)つまり「不変」という意味になります。(例:possible/impossible)

じゃあプログラミング言語的にはどういう意味かというと・・・?

イミュータブル (英: immutable) なオブジェクトとは、作成後にその状態を変えることのできないオブジェクトのことである。対義語はミュータブル (英: mutable) なオブジェクトで、作成後も状態を変えることができる。

まぁザックリいうとイミュータブルなオブジェクトだと定数的な扱いになって、再代入とかできないんですね。

え?なんでそんなメンドクサイの使うの?

って思ったのでまたまた調べてみると以下のエントリにアンサーが。

なるほどコピーの際に参照をそのまま使えるのは実行速度に大きく影響しそうですね・・・!

先ほどのWikipediaにも以下の記述が

イミュータブルなオブジェクトはマルチスレッドプログラミングにおいても有用となる。データがイミュータブルなオブジェクトで表現されていると、複数のスレッドが他のスレッドにデータを変更される心配なくデータにアクセスできる。つまり排他制御の必要がない。よってイミュータブルなオブジェクトのほうがミュータブルなものよりスレッドセーフであると考えられる。

マルチスレッドを使用する場合に排他制御などのオーバヘッドを削減する効果があるようです。

Goは実行速度が速く、ゴルーチンのように並列処理を容易に記述できる利点がありますが、その背景にはイミュータブルという概念が活用されているんですね!

イミュータブルまとめ

Rubyのように「文字列をはじめとするオブジェクトがミュータブルな言語」に慣れていると、Goの文字列処理はとっつきにくいですね。しかし、意味や利点まで理解していると、すんなり受け入れられそうです。

ミュータブルだと記述が少なくなりますが、大規模開発だと気づきにくいバグを生み出したり実行速度が遅くなる可能性があります。一方でイミュータブルだと記述が多くなってしまいますが、大規模になってもバグが生まれづらくマルチスレッドの活用やメモリ効率の面で利点があるようです。

趣味で気ままに一人で書くにはRubyが向いていて、複数人でお仕事するにはGoが向いてるのかな?

あまり詳しくないので、もし補足などあればコメントいただけると幸いです!