web-dev-qa-db-ja.com

Swift定数:構造体または列挙型

どちらを定数を定義するほうがよいかわかりません。構造体または列挙。構造体は、使用するたびにコピーされますか? static let定数を持つ構造体について考えるとき、私の意見では、常にコピーされるとは意味がありません。しかし、それがコピーされない場合、それは私が取るものに関係ありませんか?

構造体または列挙型の選択にはどのような利点がありますか?

フランシスコはStructを使用すると言います

レイワンダーリッヒはEnumを使用すると言います。しかし、私には正当性がありません。

66
Paixsn

構造体と列挙の両方が機能します。例として、両方

struct PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

そして

enum PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

動作し、静的プロパティPhysicalConstants.speedOfLightを定義します。

Re:構造体は使用するたびにコピーされますか?

structenumは両方とも値型であるため、列挙にも適用されます。しかし、ここでは無関係です値をまったく作成する必要がないためです:静的プロパティ(とも呼ばれます) typeproperties)は、その型のインスタンスではなく、型自体のプロパティです。

Re:構造体または列挙型の選択にはどのような利点がありますか?

リンク先の記事 で述べたように:

ケースレス列挙を使用する利点は、誤ってインスタンス化されず、純粋な名前空間として機能することです。

構造の場合、

let foo = PhysicalConstants()

PhysicalConstants型の(役に立たない)値を作成しますが、ケースレスの列挙の場合、コンパイルに失敗します。

let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
96
Martin R

簡単な答えを次に示します。定数は一意である必要がありますか?次に、これを強制する列挙型を使用します。

同じ値を格納するためにいくつかの異なる定数を使用したいですか?次に、これを可能にする構造体を使用します。

11
jglasse

Xcode 7.3.1およびSwift 2.2の使用

私はMartin Rに同意し、Ray Wenderlichスタイルガイドは、純粋な名前空間であるため、ほとんどすべてのユースケースでenumが優れていることを指摘していますが、structを使用するとenums

Switchステートメント

構造体のバージョンから始めましょう:

struct StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

構造体を使用すると、Matched StaticVars.someStringに一致して出力されます。

ここで、大文字と小文字のない列挙型バージョンを考えてみましょう(キーワードstructenumに変更するだけです):

enum StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

case StaticVars.someString:行のswitchステートメントでコンパイル時エラーが発生することがわかります。エラーはEnum case 'someString' not found in type 'String'です。

静的プロパティを代わりに型を返すクロージャに変換することにより、擬似的な回避策があります。

したがって、次のように変更します。

enum StaticVars {
    static let someString = { return "someString" }
}

switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

関数になったため、caseステートメントに括弧が必要であることに注意してください。

欠点は、関数にしたので、呼び出されるたびに実行されることです。したがって、StringIntのような単純なプリミティブ型であれば、それほど悪くはありません。本質的には計算されたプロパティです。計算が必要な定数で、一度だけ計算したい場合は、別のプロパティに計算して、計算済みの値をクロージャーに返すことを検討してください。

デフォルトのイニシャライザをプライベートなものでオーバーライドすることもできます。そうすると、ケースレス列挙型と同じ種類のコンパイル時エラーが発生します。

struct StaticVars {
    static let someString = "someString"
    private init() {}
}

ただし、これを使用すると、たとえばView Controllerクラスと同じファイルで宣言した場合、そのクラスのファイルが誤って役に立たないインスタンスを作成する可能性があるため、構造体の宣言を独自のファイルに配置する必要がありますStaticVarsのインスタンスですが、クラスのファイルの外では意図したとおりに動作します。しかし、それはあなたの電話です。

4
Tim Fuqua