迅速な言語での構造とクラス


192

Appleの本から「構造体とクラスの最も重要な違いの1つは、構造体はコード内で渡されるときに常にコピーされるが、クラスは参照によって渡されることです。」

誰かが私がそれが何を意味するのか理解するのを手伝ってくれる?私にとって、クラスと構造体は同じように見えます。


3
.NETの構造体とクラスの違いを参照してください:stackoverflow.com/a/13275/19100、Swiftが同じセマンティクスを使用していると思います。
ダレ2014年

23
@jonrsharpeはあなたにとって簡単でしょうか?あなたがこれを知っているなら、あなたは私に答えを与えることができます
マニッシュアグラワル

1
値と参照はOOPのみの概念ではありません。void my_func(int a)vsのように、Cにもありvoid my_func(int &a)ます。これはプログラミングの非常に基本的な問題です。さらに読む:stackoverflow.com/questions/373419/...
superarts.org

回答:


473

これは、の例classです。名前が変更されると、両方の変数によって参照されるインスタンスが更新されることに注意してください。Bobは今Sue、どこでもBob参照されていました。

class SomeClass {
    var name: String
    init(name: String) {
        self.name = name
    }
}

var aClass = SomeClass(name: "Bob")
var bClass = aClass // aClass and bClass now reference the same instance!
bClass.name = "Sue"

println(aClass.name) // "Sue"
println(bClass.name) // "Sue"

これstructで、値がコピーされ、各変数が独自の値のセットを保持していることがわかります。名前をに設定してSueも、Bob構造体はaStruct変更されません。

struct SomeStruct {
    var name: String
    init(name: String) {
        self.name = name
    }
}

var aStruct = SomeStruct(name: "Bob")
var bStruct = aStruct // aStruct and bStruct are two structs with the same value!
bStruct.name = "Sue"

println(aStruct.name) // "Bob"
println(bStruct.name) // "Sue"

したがって、ステートフルで複雑なエンティティを表すには、a classは素晴らしいです。ただし、単に測定値または関連データのビットである値の場合、structをコピーして簡単にコピーしたり、副作用を心配することなく値を変更したりできるようにする方が理にかなっています。


「しかし、単なる数よりも複雑ではない値について...」このアレックスをありがとう
マイク・ラパダス2014

7
@MichaelRapadas Numbersは、実際に Swiftの構造体です。
ニコライルーエ2014

aStruct and bStruct are two structs with the same value!構造体の内部の変数の値が異なるため、これを混乱させますか?
JulianKról15年

@JulianKrólその行aStructbStruct同じ値を持ちます。どちらにも、1つのnameフィールドが設定されてい"Bob"ます。しかし、それらは2つの異なる構造体です。これは、構造体の1つの名前を変更でき、他の構造体は変更されない場合に、次の行で証明されます。
Alex Wayne

割り当てを逃しただけです。明らかです、ありがとう。多分それは外で暑すぎる:-)
JulianKról2015

60

クラスと構造の両方で実行できます。

  • 値を格納するプロパティを定義する
  • 機能を提供するメソッドを定義する
  • 伸びる
  • プロトコルに準拠
  • 初期化子を定義する
  • 変数へのアクセスを提供する添え字を定義する

クラスだけが行うことができます:

  • 継承
  • 型キャスト
  • deinitialisersを定義する
  • 複数の参照の参照カウントを許可します。

32

struct値タイプです。つまり、構造体のインスタンスを別の変数にコピーすると、変数にコピーされるだけです。

値タイプの例

struct Resolution {
    var width = 2
    var height = 3
}

let hd = Resolution(width: 1920, height: 1080)
var cinema = hd //assigning struct instance  to variable
println("Width of cinema instance is \(cinema.width)")//result is 1920
println("Width of hd instance is \(hd.width)")//result is 1920

cinema.width = 2048

println("Width of cinema instance is \(cinema.width)")//result is 2048
println("Width of hd instance is \(hd.width)")//result is 1920

クラスは参照型です。それはあなたが変数にクラスのインスタンスを割り当てた場合、それだけで保持することを意味し、参照インスタンスとのコピーではありませんが


5
「クラスのインスタンスを別の変数に割り当てる場合、コピーではなくインスタンスの参照のみを保持します。」の+1
2015年

8

上記の答えは正しいです。私の答えが上記の答えを理解していない人の助けになることを願っています。

Well in Swiftには2種類のオブジェクトがあります

  1. ストラクト
  2. クラス

それらの主な違いは

  • 構造体は型です
  • クラスは参照型です

たとえば、ここではコードをよく理解します。

struct SomeStruct {
var a : Int;

init(_ a : Int) {
    self.a = a
}
}

class SomeClass {
var a: Int;

init(_ a: Int) {
    self.a = a
}

}
var x = 11

var someStruct1 = SomeStruct(x)
var someClass1 = SomeClass(x)

var someStruct2 = someStruct1
var someClass2 = someClass1

someClass1.a = 12
someClass2.a // answer is 12 because it is referencing to class 1     property a

someStruct1.a = 14
someStruct2.a // answer is 11 because it is just copying it not referencing it

これが主な違いでしたが、副次的な違いもあります。

クラス

  1. イニシャライザ(コンストラクタ)を宣言する必要があります
  2. deinitialisersあり
  3. 他のクラスから継承できます

ストラクト

  1. 無料のイニシャライザがあります。宣言したイニシャライザによって無料のイニシャライザが上書きされる場合は、イニシャライザを宣言する必要はありません。
  2. deinitialiserを持っていない
  3. 他の構造体から継承できません

7

この質問は重複しているようですが、いずれにせよ、以下はほとんどのユースケースに答えます。

  1. 構造体とクラスの最も重要な違いの1つは、構造体は値の型であり、コード内で渡されると常にコピーされること、クラスは参照型であり、参照によって渡されることです。

  2. また、クラスには1つのクラスが別のクラスの特性を継承できるようにする継承があります。

  3. 構造体のプロパティはスタックに格納され、クラスのインスタンスはヒープに格納されるため、スタックがクラスよりも大幅に高速になる場合があります。

  4. Structはデフォルトの初期化子を自動的に取得しますが、Classでは初期化する必要があります。

  5. Structはいつでもスレッドセーフまたはシングルトンです。

また、構造体とクラスの違いを要約するには、値と参照型の違いを理解する必要があります。

  1. 値型のコピーを作成すると、コピーするものからすべてのデータが新しい変数にコピーされます。これらは2つの独立したものであり、一方を変更しても他方には影響しません。
  2. 参照型のコピーを作成すると、新しい変数は、コピーしているものと同じメモリ位置を参照します。つまり、どちらも同じメモリ位置を参照しているため、一方を変更すると他方も変更されます。下記のサンプルコードは参考にしてください。

// sampleplayground.playground

  class MyClass {
        var myName: String
        init(myName: String){
            self.myName = myName;
        }
    }

    var myClassExistingName = MyClass(myName: "DILIP")
    var myClassNewName = myClassExistingName
    myClassNewName.myName = "John"


    print("Current Name: ",myClassExistingName.myName)
    print("Modified Name", myClassNewName.myName)

    print("*************************")

    struct myStruct {
        var programmeType: String
        init(programmeType: String){
            self.programmeType = programmeType
        }
    }

    var myStructExistingValue = myStruct(programmeType: "Animation")
    var myStructNewValue = myStructExistingValue
    myStructNewValue.programmeType = "Thriller"

    print("myStructExistingValue: ", myStructExistingValue.programmeType)
    print("myStructNewValue: ", myStructNewValue.programmeType)

出力:

Current Name:  John
Modified Name John
*************************
myStructExistingValue:  Animation
myStructNewValue:  Thriller

こんにちはディリップ、「Structはいつでもスレッドセーフまたはシングルトンです。」の例を挙げていただけますか?前もって感謝します。
Narasimha Nallamsetty

3

アップルハンドブックをさらに詳しく見ると、「構造と列挙は値の型」というセクションが表示されます。

このセクションでは、次のようになります。

“ let hd = Resolution(width:1920、height:1080)var cinema = hdこの例では、hdという定数を宣言し、それを解像度に設定しますフルHDビデオの幅と高さ(幅1920ピクセル、高さ1080ピクセル)で初期化されたインスタンス。

次に、cinemaという変数を宣言し、それを現在のhdの値に設定します。解像度は構造であるため、既存のインスタンスのコピーが作成され、この新しいコピーが映画館に割り当てられます。hdと映画の幅と高さは同じになりましたが、舞台裏では2つのまったく異なるインスタンスです。

次に、映画のwidthプロパティは、デジタルシネマプロジェクションに使用されるわずかに広い2K標準の幅(幅2048ピクセル、高さ1080ピクセル)に修正されます。

cinema。width = 2048 cinemaのwidthプロパティを確認すると、実際に2048に変更されています:

println( "cinema is now(cinema。width)pixels width")//を印刷します「cinema is now 2048 pixel wide 1920の値:

println( "hd is still(hd。width)pixel width")//「hd is still 1920 pixel width」を出力します

シネマに現在のhdの値が指定されると、hdに格納されている値が新しいシネマインスタンスにコピーされました。最終結果は2つの完全に異なるインスタンスで、たまたま同じ数値が含まれています。それらは別個のインスタンスであるため、映画の幅を2048に設定しても、hdに格納されている幅には影響しません。」

抜粋:Apple Inc.「The Swift Programming Language」iBooks。 https://itun.es/us/jEUH0.l

これは、構造体とクラスの最大の違いです。構造体がコピーされ、クラスが参照されます。


1

通常(ほとんどのプログラミング言語では)、オブジェクトはヒープに格納されるデータのブロックであり、これらのブロックへの参照(通常はポインター)には、nameこれらのデータブロックへのアクセスに使用されています。このメカニズムでは、参照(ポインタ)の値をコピーすることにより、ヒープ内のオブジェクトを共有できます。これは、整数などの基本的なデータ型の場合とは異なります。これは、参照の作成に必要なメモリがオブジェクト(この場合は整数値)とほとんど同じであるためです。したがって、それらは大きなオブジェクトの場合、参照としてではなく値として渡されます。

Swiftは、StringおよびArrayオブジェクトを使用してもパフォーマンスを向上させるためにstructを使用します。

ここで本当に良い読書


1

構造体とクラスの違いを理解するには、値と参照型の主な違いを知る必要があります。構造体は値の型であり、それらのすべての変更はその値を変更するだけであり、クラスは参照型であり、参照型のすべての変更はメモリまたは参照のその場所に割り当てられた値を変更します。例えば:

クラスでレッツ・スタート、Equatableにこのクラスの準拠は、単にインスタンスを比較できるようにするには、我々はと呼ばれるインスタンスの作成pointClassInstanceAと呼ばれ、他のpointClassInstanceBクラスBに我々アサインクラスAを、今主張は、彼らが同じであることを述べています...

class PointClass: Equatable {
    var x: Double
    var y: Double

    init(x: Double, y: Double) {
        self.x = x
        self.y = y
    }

    static func == (lhs: PointClass, rhs: PointClass) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}

var pointClassInstanceA = PointClass(x: 0, y: 0)
var pointClassInstanceB = pointClassInstanceA

assert(pointClassInstanceA==pointClassInstanceB) 

pointClassInstanceB.x = 10
print(pointClassInstanceA.x)
//this prints 10

では、pointsClassInstanceBのx値を変更しただけで、pointClassInstanceAのx値も変更されたのはなぜですか。これは、インスタンスBの値としてインスタンスAを割り当てた後、参照タイプがどのように機能するかを示しています。次に、どちらか一方のXを変更すると、両方が同じ参照を共有するため、両方のXが変更され、変更されたのはその値でした。参照。

同じことをしますが、構造体で

struct PointStruct: Equatable {
    var x: Double
    var y: Double

    init(x: Double, y: Double) {
        self.x = x
        self.y = y
    }

    static func == (lhs: PointStruct, rhs: PointStruct) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}
var pointStructInstanceA = PointStruct(x: 0, y: 0)
var pointStructInstanceB = pointStructInstanceA

assert(pointStructInstanceA==pointStructInstanceB)
pointStructInstanceB.x = 100
print(pointStructInstanceA.x)
//this will print 0

基本的にはクラスと同じ構造ですが、pointStructInstanceAのx値を出力しても変化しなかったことがわかります。これは、値の型の動作が異なり、インスタンスの1つに対するすべての変更が "独立」し、他には影響しません。

Swiftはより多くの値タイプを使用することを提案しており、それらのライブラリは構造体に基づいているため、参照タイプがもたらす問題(意図せずに値を変更するなど)を回避できます。構造体はSwiftを使用する方法です。それが役に立てば幸い。


1

これは、構造体とクラスの違いを正確に示す例です。

遊び場で書かれたコードのスクリーンショット
遊び場で書かれたコードのスクリーンショット

struct Radio1{
    var name:String
    //    init(name:String) {
    //        self.name = name
    //    }
}

struct Car1{
    var radio:Radio1?
    var model:String

}

var i1 = Car1(radio: Radio1(name:"murphy"),model:"sedan")
var i2 = i1
//since car instance i1 is a struct and 
//this car has every member as struct ,
//all values are copied into i2

i2.radio?.name //murphy
i2.radio = Radio1(name: "alpha")
i2.radio?.name //alpha

i1.radio?.name //murphy

//since Radio1 was struct , 
//values were copied and thus
// changing name  of instance of Radio1 in i2 
//did not bring change in i1

class Radio2{
    var name:String
    init(name:String) {
        self.name = name
    }
}

struct Car2{
    var radio:Radio2?
    var model:String

}
var i3 = Car2(radio: Radio2(name:"murphy"),model:"sedan")
//var radioInstance = Radio2(name: "murphy")
//var i3 = Car2(radio: radioInstance,model:"sedan")

var i4 = i3
//since i3 is instance of struct
//everything is copied to i4 including reference of instance of Radio2
//because Radio2 is a class



i4.radio?.name //murphy
i4.radio?.name="alpha"
i4.radio?.name //alpha

i3.radio?.name //alpha

//since Radio2 was class, 
//reference was copied and 
//thus changing name of instance 
//of Radio2 in i4 did  bring change in i3 too


//i4.radio?.name
//i4.radio = Radio2(name: "alpha")
//i4.radio?.name
//
//i3.radio?.name

1
1.structure is value type.
   = > when we assign structure variable to other variable or pass as parameter to function, it creates separate/new copy => so that changes made on one variable does not  reflect on another.[We can say like **call by value** concept] 
Example :

    struct DemoStruct 
    { 
        var value: String 
        init(inValue: String) 
        { 
            self.value = inValue 
        } 
    } 


var aStruct = DemoStruct(inValue: "original") 
var bStruct = aStruct // aStruct and bStruct are two structs with the same value! but references to diff location`enter code here`
bStruct.value = "modified" 

print(aStruct.value) // "original" 
print(bStruct.value) // "modified"


2.class is reference type.
 = > when we assign structure variable to other variable or pass as parameter to function, it **does not** creates separate/new copy => so that changes made on one variable does not  reflect on another.[We can say like **call by reference** concept] 
Example:
class DemoClass 
{   
    var value: String 
    init(inValue: String) 
    {
        self.value = inValue 
    } 
} 

var aClass = DemoClass(inName: "original") 
var bClass = aClass // aClass and bClass now reference the same instance! 
bClass.value = "modified" 

print(aClass.value) // "modified" 
print(bClass.value) // "modified"

1

スウィフトタイプ

Value type 変数または定数に割り当てられたとき、または関数に渡されたときに値がコピーされる型です

Reference types 変数または定数に割り当てられたとき、または関数に渡されたときはコピーされません

値のタイプ
StructEnumTuple
struct Stringstruct ArraySetDictionary

  • あなたはときに割り当てたり、パス value typeの新しいコピーデータのが作成されます。実際copy on write- COWメカニズムは、オブジェクトが変更されたときにコピーが作成され、例えば、いくつかの最適化で使用され
  • インスタンスを変更するとローカルにのみ影響があります。
  • スタックメモリが使用されています。

参照タイプ
ClassFunction

  • 元のインスタンスへの新しい参照を割り当てるか渡すとreference type、作成されます(インスタンスのアドレスがコピーされます)。
  • インスタンスを変更すると、インスタンスはそれを指す参照によって共有され、アクセスできるため、グローバルな効果があります。
  • ヒープメモリが使用されています。

ここに画像の説明を入力してください

Value typeデフォルトで使用することをお勧めします。の最大の利点Value typeは、通常、thread safe

Reference type 長所:

  • 彼らは継承することができ、
  • deinit() に使える、
  • 参照===でインスタンスを比較する、
  • Objective-CValue TypeSwiftで導入されたため、相互運用性。

[可変性の詳細]
構造とクラスの
タイプの選択
クラスと構造


0

いつもこれについてたくさん書かれています、そこに類推を加えたいと思います。この後、あなたが疑うことは決してないことを願っています:結論: クラスは参照によって渡されますが、構造体は値によって渡されます。

友人とGoogleドキュメントシートを共有しているとします。ここで彼が何かを変更すると、Googleドキュメントの変更も表示されます。つまり、コピーにも影響があります。基本的には「参照渡し」です。

しかし、マシンに.XLSファイルが保存されているとしましょう。あなたはあなたの友人に与えるそのファイルを提供します。今、彼がそのファイルに変更を加えている場合、あなた自身のコピーがあるので、あなたのファイルはめちゃくちゃになったり影響を受けたりしません。基本的には「値渡し」です。このアナロジーを迅速なプレイグラウンドで確認するために、すでに複数の単純なプログラムがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.