Edited at

クラスと構造体の使い分け

More than 3 years have passed since last update.

VB.NETの開発中、ちょっと目を離した隙にStructureでやりくりしようとしてるプログラムが蔓延してしまった・・・

油断ならんので、今後新しい開発するときの視点に加えよう。


MSDN 曰く


引用元:クラスまたは構造体の選択

クラスは参照型ですが、構造体は値型です。 参照型はヒープ上に割り当てられ、メモリ管理はガベージ コレクターによって処理されます。

値型はスタックまたはインライン上に割り当てられ、スコープの外に出たときに解放されます。 一般に、割り当てや解放は値型の方が簡単です。 ただし、大量のボックス化とボックス化解除が必要なシナリオで使用すると、参照型と比べてパフォーマンスが低くなります。 詳細については、「ボックス化とボックス化解除 (C# プログラミング ガイド)」を参照してください。

型のインスタンスが小さく有効期間が一般に短い場合や、型のインスタンスが一般に他のオブジェクト内に埋め込まれる場合は、クラスではなく、構造体を定義することを検討します。

型が次に挙げるすべての特性を持たない場合、構造体は定義しません。


  • プリミティブ型 (整数、倍精度浮動小数点数など) に似た単一の値を論理的に表す。

  • インスタンスのサイズが 16 バイト未満である。

  • 変更できない。

  • 頻繁にボックス化する必要がない。

これらの条件を 1 つ以上満たしていない場合は、構造体ではなく、参照型を作成します。 このガイドラインに従わない場合、パフォーマンスが低下する可能性があります。


特に問題がありそうな箇所について「こういうことだから、ここは構造体じゃなくてクラス使ってね」なんて指示していると、次のような言葉が返って来ました。


「クラスって万能ですね!」


よくよく考えたら、なんでVB.NETは構造体が値型で動くんだろうか?

ややこしいし、全部連想配列にしてしまえばいいじゃん。まぁPHPは連想配列オンリーやめたおかげでパフォーマンス上がったんだけど・・・


VS.「全部クラスでよくね?」


引用元:Swiftことはじめ:String?のクエスチョンマークって何?

このようにSwiftではデフォルトでは変数にnilが入らないようになっており、

nilを代入したい場合は型に?を付けた型で宣言します。



なんでこんな言語仕様があるの?

結論から言ってしまうと「コンパイル時点でnilをチェックするため」です。

通常のnullチェックの場合、以下の様な欠点がありました。


  • nullになり得るかどうかをプログラマが考える必要がある→対応忘れが頻繁に起きる

  • ほんとにnullになるかどうかは実行時にわかる→ストア配布後などにテスト漏れによるnilに起因したクラッシュが発生する

こうした状況に対処できるのが今回説明しているoptional valueです。

上記の欠点についてoptional valueなら次のことが言えます。


  • nullになり得るかどうかは型で把握しているのでコンパイラが判断できる

  • ほんとにnullになるかどうかはコンパイル時点でわかる

つまり今まではプログラマが考えたり実行してテストしていたものをコンパイラという機械にまかせてしまうことができます。


なるほど、こういう考え方もあるのね。

私はプログラム書くときは、入口で弾いて値域絞るタイプだから、こういう思想はわかる。


まとめ

コンパイラに任せる範囲、プロジェクトに用意するガイドラインの厳しさ/緩さ、プロジェクトメンバーに求める責任範囲とかと照らし合わせて、言語選定の材料になりそう。