hızlı dilde yapıya karşı yapı


192

"Yapılar ve sınıflar arasındaki en önemli farklardan biri, yapıların kodunuzda iletildiklerinde her zaman kopyalanması, ancak sınıfların referans olarak geçirilmesidir."

Herkes bunun ne anlama geldiğini anlamama yardımcı olabilir mi? Bana göre, sınıflar ve yapılar aynı görünüyor.


3
.NET'te struct ve sınıf arasındaki farkı görün: stackoverflow.com/a/13275/19100 , Swift'in aynı anlambilimi kullandığını tahmin ediyorum.
dalle

23
@jonrsharpe sizin için kolay olabilir mi? bunu biliyorsan bana cevabı verebilir misin
Manish Agrawal

1
Referansa karşılık değer, yalnızca OOP kavramı değildir. Sanki, C var void my_func(int a)vs void my_func(int &a). Bu çok temel bir programlama sorusudur. Daha fazla bilgi için: stackoverflow.com/questions/373419/…
superarts.org

Yanıtlar:


473

İşte a ile bir örnek class. Ad değiştirildiğinde, her iki değişken tarafından başvurulan örneğin nasıl güncellendiğini unutmayın. Bobşimdi Sue, Bobreferans verilen her yerde .

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"

Ve şimdi bir ile structdeğerlerin kopyalandığını ve her değişkenin kendi değer kümesini koruduğunu görüyoruz. Biz adını ayarladığınızda Sue, Bobiçinde yapı aStructdeğişti almaz.

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"

Durumsal karmaşık bir varlığı temsil etmek için a classharika. Ancak sadece ilgili verilerin bir ölçümü veya bitleri olan değerler için struct, daha kolay bir şekilde mantıklıdır, böylece bunları kolayca kopyalayabilir ve onlarla hesaplayabilir veya yan etkilerden korkmadan değerleri değiştirebilirsiniz.


"Ama sadece bir sayıdan daha karmaşık olmayan değerler için ..." Bunun için teşekkürler Alex
Mike Rapadas

7
@MichaelRapadas Numaraları aslında olan Swift yapılar.
Nikolai Ruhe

Bunu açıklayabilir misiniz aStruct and bStruct are two structs with the same value!yapı içindeki değişkenlerin değerleri farklı olarak bu karıştırır beni.
Julian Król

@ JulianKról O satır aStructve bStructaynı değerlere sahip. Her ikisinin de nameayarlanan tek bir alanı vardır "Bob". Ancak bunlar iki farklı yapıdır. Bu, yapılardan birinin adını değiştirebileceğiniz ve diğerinin değişmeden kaldığı bir sonraki satırda kanıtlanmıştır.
Alex Wayne

Görevi kaçırdım. Çok açık, teşekkürler. Belki dışarıda çok sıcak :-)
Julian Król

60

Hem sınıf hem de yapı şunları yapabilir:

  • Değerleri saklamak için özellikleri tanımlama
  • İşlevsellik sağlamak için yöntemler tanımlama
  • Uzatılmak
  • Protokollere uygunluk
  • Başlatıcıları tanımlayın
  • Değişkenlerine erişim sağlamak için Abonelikleri tanımlayın

Sadece sınıf şunları yapabilir:

  • miras
  • Tip döküm
  • Deinitialisers tanımlayın
  • Birden çok referans için referans sayımına izin ver.

32

structdeğer türleridir. Bu, yapının örneğini başka bir değişkene kopyalarsanız, sadece değişkene kopyalandığı anlamına gelir.

Değer Türü Örneği

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

Sınıflar referans türleridir. Bu, bir değişkene sınıfın bir örneğini atarsanız , kopyaya değil, yalnızca örneğe yapılan başvuruyu tutacağı anlamına gelir .


5
+1 "Sınıfın bir örneğini başka bir değişkene atarsanız, yalnızca kopyalanmayan örneğin referansını tutar."
Saif

8

Yukarıdaki cevaplar doğrudur Umarım cevabım yukarıdaki cevapları anlamayan birine yardımcı olacaktır.

Swift'te iki tür nesne var

  1. struct
  2. Sınıf

Aralarındaki temel fark

  • Yapı değer tipidir
  • Sınıf referans türüdür

Örneğin burada iyi anlamak için kod.

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

Bu ana farktı, ancak alt farklarımız da var.

Sınıf

  1. Başlatıcı (yapıcı) beyan etmelidir
  2. Deinitialisers var
  3. Diğer sınıflardan miras alabilir

struct

  1. Sizin için ücretsiz başlatıcısı vardır, ücretsiz başlatıcısı beyan ettiğiniz başlatıcı tarafından üzerine yazılacaksa, başlatıcı ilan etmek zorunda değilsiniz
  2. Deinitialiser yok
  3. Diğer yapıdan devralınamaz

7

Bu soru yineleniyor gibi görünse de, aşağıdakiler kullanım durumunun çoğuna cevap verecektir:

  1. Yapılar ve sınıflar arasındaki en önemli farklardan biri, yapıların değer türleridir ve kodunuzda iletildiklerinde her zaman kopyalanırlar ve sınıflar referans türüdür ve referans olarak iletilir.

  2. Ayrıca sınıflar, bir sınıfın diğerinin özelliklerini miras almasına izin veren Kalıtım özelliğine sahiptir.

  3. Yapı özellikleri Yığın üzerinde saklanır ve Sınıf örnekleri Yığın üzerinde saklanır, bu nedenle bazen yığın bir sınıftan çok daha hızlıdır.

  4. Struct otomatik olarak varsayılan bir başlatıcı alırken, Class'ta başlatmamız gerekir.

  5. Yapı, herhangi bir zamanda iş parçacığı için güvenli veya tekli.

Ve ayrıca, yapılar ve sınıflar arasındaki farkı özetlemek için, değer ve referans türleri arasındaki farkı anlamak gerekir.

  1. Bir değer türünün kopyasını oluşturduğunuzda, kopyaladığınız şeydeki tüm verileri yeni değişkene kopyalar. Bunlar 2 ayrı şeydir ve birini değiştirmek diğerini etkilemez.
  2. Referans türünün bir kopyasını oluşturduğunuzda, yeni değişken kopyaladığınız şeyle aynı bellek konumuna başvurur. Bu, her ikisinin de aynı bellek konumuna başvurduğu için birini değiştirmenin diğerini değiştireceği anlamına gelir. Aşağıdaki örnek kod referans olarak alınabilir.

// 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)

Çıktı:

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

Merhaba Dilip, "Yapı herhangi bir zamanda iş parçacığı güvenli veya singleton" için bir örnek verebilir misiniz ?. Şimdiden teşekkürler.
Narasimha Nallamsetty

3

Elma el kitabında daha uzağa bakarsanız bu bölümü göreceksiniz: “Yapılar ve Numaralamalar Değer Türleridir”

Bu bölümde şunu göreceksiniz:

“Let hd = Çözünürlük (genişlik: 1920, yükseklik: 1080) var cinema = hd Bu örnek hd adlı bir sabit bildirir ve bir Çözünürlük olarak ayarlar tam HD videonun genişliği ve yüksekliği ile başlatılan örnek (1920 piksel genişlik ve 1080 piksel yükseklik).

Daha sonra sinema adı verilen bir değişkeni bildirir ve onu hd'in geçerli değerine ayarlar. Çözünürlük bir yapı olduğundan, varolan örneğin bir kopyası oluşturulur ve bu yeni kopya sinemaya atanır. HD ve sinema artık aynı genişlik ve yüksekliğe sahip olsa da, sahne arkasında tamamen farklı iki örnek.

Ardından, sinemanın width özelliği, dijital sinema projeksiyonu için kullanılan biraz daha geniş 2K standardının genişliği olarak değiştirildi (2048 piksel genişlik ve 1080 piksel yükseklik):

Width = 2048 Sinemanın width özelliğinin kontrol edilmesi, gerçekte 2048 olarak değiştiğini gösterir:

Println ("sinema şimdi (sinema. Genişlik) piksel genişliğinde") // baskılar "sinema şimdi 2048 piksel genişliğinde Ancak orijinal hd örneğinin width özelliği hala eski 1920 değeri:

println ("hd hala (hd. genişlik) piksel genişliğinde") // yazdırır "hd hala 1920 piksel genişliğinde"

Sinemaya geçerli hd değeri verildiğinde, hd'de depolanan değerler yeni sinema örneğine kopyalandı. Nihai sonuç, aynı sayısal değerleri içerdiği iki tamamen ayrı örnektir. Ayrı örnekler oldukları için sinemanın genişliğini 2048 olarak ayarlamak hd'de depolanan genişliği etkilemez. ”

Alıntı: Apple Inc. “Hızlı Programlama Dili.” iBooks. https://itun.es/us/jEUH0.l

Bu, yapılar ve sınıflar arasındaki en büyük farktır. Yapılar kopyalanır ve sınıflara başvurulur.


1

Genellikle (çoğu programlama dilinde), nesneler yığın üzerinde depolanan veri bloklarıdır ve daha sonra bu bloklara bir referans (normalde bir işaretçi), bu nameveri bloklarına erişmek için bir a içerir . Bu mekanizma, referanslarının (işaretçiler) değerini kopyalayarak öbekteki nesneleri paylaşmaya izin verir. Bu, Tamsayılar gibi temel veri türleri için geçerli değildir ve bunun nedeni, bir başvuru oluşturmak için gereken belleğin nesne ile hemen hemen aynı olmasıdır (bu durumda tamsayı değeri). Böylece, büyük nesneler için referans olarak değil, değerler olarak aktarılacaktır.

Swift, String ve Array nesnelerinde bile performansı artırmak için struct kullanır.

Burada gerçekten iyi bir okuma


1

Yapılar ve Sınıflar arasındaki farkı anlamak için değer ve referans türleri arasındaki temel farkı bilmemiz gerekir. Yapılar değer tipleridir ve bu, üzerlerindeki her değişikliğin sadece bu değeri değiştireceği, Sınıfların referans tipler olduğu ve referans tipindeki her değişikliğin o bellek veya referans yerine tahsis edilen değeri değiştireceği anlamına gelir. Örneğin:

Bir Sınıfla başlayalım, bu sınıf sadece örnekleri karşılaştırmak için Eşittir'e uyuyor, denilen bir örnek yaratıyoruz pointClassInstanceAve pointClassInstanceBB sınıfına A sınıfı atadığımız diğer bir örnek oluşturuyoruz , şimdi iddia aynı olduklarını söylüyor ...

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

Tamam, burada ne oldu, sadece pointsClassInstanceB'nin x değerini değiştirirsek, aynı zamanda pointClassInstanceA'nın x değerini de değiştirdi mi? Bu, referans türlerinin nasıl çalıştığını gösterir, A örneğini B örneğinin değeri olarak atadığımızda ve bunlardan birinin X'ini değiştiririz, aynı referansı paylaştıkları ve bunun değerinin ne olduğu değiştiğinden, her iki X'i de değiştirir referans.

Aynı şeyi yapalım ama bir yapıyla

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

Temelde sınıfımızla aynı yapıya sahibiz, ancak şimdi pointStructInstanceA'nın x değerini yazdırdığınızda bu durumun değişmediğini ve bunun değer türlerinin farklı çalıştığını ve örneklerinden birindeki her değişikliğin " bağımsız "ve diğerini etkilemez.

Swift, daha fazla değer türü kullanmanızı önerir ve kitaplıklarının referans türlerinin getirdiği sorunlardan kaçınmak için istem dışı bir değeri vb. Umarım yardımcı olur.


1

Yapı ve sınıf arasındaki farkı tam olarak gösteren bir örnek.

oyun alanında yazılı kodun ekran görüntüsü
oyun alanında yazılı kodun ekran görüntüsü

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

Swift türleri

Value type değişkeni veya değişkeni atandığında veya bir işleve iletildiğinde değeri kopyalanan bir türdür

Reference types bir değişkene veya sabite atandıklarında veya bir işleve iletildiklerinde kopyalanmazlar

Değer Tipi :
Struct, Enum, Tuple
struct String, struct Array( Set, Dictionary)

  • Ne zaman atayabilir veya geçmesi value type yeni bir kopya veri oluşturulur. Aslında copy on write- COWmekanizması bazı optimizasyonlarda kullanılır, örneğin nesne değiştirildiğinde kopya oluşturulur
  • Bir örneği değiştirdiğinizde bunun yalnızca yerel etkisi olur.
  • Yığın Bellek kullanılır.

Referans Tipi :
Class,Function

  • Atamak veya geçirdiğinizde reference typebir yeni referans orijinal örneğine oluşturulacak (örneğinin adres kopyalanır).
  • Bir örneği değiştirdiğinizde , bunun üzerine işaret eden herhangi bir başvuru tarafından paylaşıldığı ve erişilebilir olduğu için bunun global bir etkisi vardır .
  • Öbek Bellek kullanılır.

resim açıklamasını buraya girin

Value typevarsayılan olarak kullanılması önerilir . En büyük avantajı Value typegenelliklethread safe

Reference type Artıları:

  • kalıtsal olabilirler,
  • deinit() kullanılabilir,
  • örnekleri referans ile karşılaştırma ===,
  • Objective-Cbirlikte çalışabilirlik çünkü Value TypeSwift'te tanıtıldı.

[Daha fazla yaklaşık Mutability]
Yapılar ve Sınıflar Arasında Seçim
Türleri
Sınıflar Ve Yapıları


0

Alreday bu konuda çok şey yazılmış, orada bir benzetme eklemek istiyorum. Bundan sonra asla aklınızdan hiç kuşku duymayacağınızı umuyoruz: Alt satır: sınıflar referansla geçirilirken, yapılar değere göre aktarılır.

Bir google dokümanını arkadaşınızla paylaştığınızı varsayalım. Şimdi bu konuda bir şey değiştirirse, google dokümanınızdaki değişikliklerin de kopyanızın da etkilendiği anlamına gelir. Bu temel olarak " referans ile geçti ".

Ama varsayalım ki, makinenize kaydedilmiş bir .XLS beslemeniz varsa. Bu dosyayı arkadaşınıza verin. Şimdi bu dosyada herhangi bir değişiklik yapıyorsa, kendi kopyanız olduğu için dosyanız dağıtılmayacak / etkilenmeyecektir. Bu temel olarak " değere göre geçti ". Hızlı oyun alanlarında bu benzetmeyi kontrol etmek için çok sayıda basit programınız var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.