struttura vs classe in un linguaggio veloce


192

Dal libro di Apple "Una delle differenze più importanti tra strutture e classi è che le strutture vengono sempre copiate quando vengono passate nel codice, ma le classi vengono passate per riferimento".

Qualcuno può aiutarmi a capire cosa significa? Per me, le classi e le strutture sembrano essere le stesse.


3
Vedi distinzione tra struct e class in .NET: stackoverflow.com/a/13275/19100 , immagino che Swift usi la stessa semantica.
dalle

23
@jonrsharpe potrebbe essere facile per te? puoi darmi la risposta se lo sai
Manish Agrawal,

1
Valore vs riferimento non è un concetto solo OOP. E 'lì in C, come void my_func(int a)vs void my_func(int &a). Questa è una questione fondamentale della programmazione. Per saperne di più: stackoverflow.com/questions/373419/…
superarts.org

Risposte:


473

Ecco un esempio con a class. Si noti come quando si modifica il nome, viene aggiornata l'istanza a cui fanno riferimento entrambe le variabili. Bobè ora Sue, ovunque Bobsia mai stato fatto riferimento.

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"

E ora con un structvediamo che i valori vengono copiati e ogni variabile mantiene il proprio set di valori. Quando impostiamo il nome su Sue, la Bobstruttura aStructnon viene modificata.

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"

Quindi, per rappresentare un'entità complessa con stato, a classè fantastico. Ma per valori che sono semplicemente una misura o bit di dati correlati, è structpiù sensato in modo da poterli facilmente copiare e calcolare con essi o modificare i valori senza timore di effetti collaterali.


"Ma per valori che non sono più complessi di un semplice numero ..." Grazie per questo Alex
Mike Rapadas,

7
@MichaelRapadas I numeri in realtà sono strutture in Swift.
Nikolai Ruhe,

Potresti chiarire questo, aStruct and bStruct are two structs with the same value!questo mi confonde poiché i valori delle variabili all'interno della struttura sono diversi.
Julian Król,

@ JulianKról A quella linea aStructe bStructhanno valori identici. Entrambi hanno un singolo namecampo che è impostato il "Bob". Ma sono due diverse strutture. Ciò è dimostrato nella riga successiva quando è possibile modificare il nome di una delle strutture e l'altra rimane invariata.
Alex Wayne,

Ho appena perso l'incarico. È chiaro, grazie. Forse è troppo caldo fuori :-)
Julian Król l'

60

Sia la classe che la struttura possono fare:

  • Definire le proprietà per memorizzare i valori
  • Definire i metodi per fornire funzionalità
  • Essere esteso
  • Conforme ai protocolli
  • Definire gli inizializzatori
  • Definire gli abbonati per fornire l'accesso alle loro variabili

Solo la classe può fare:

  • Eredità
  • Digitare casting
  • Definire i deinitializzatori
  • Consenti il ​​conteggio dei riferimenti per più riferimenti.

32

structsono tipi di valore. Significa che se copi l'istanza della struttura in un'altra variabile, viene semplicemente copiata nella variabile.

Esempio per Tipo valore

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

Le classi sono tipi di riferimento. Significa che se assegni un'istanza della classe a una variabile, conterrà solo il riferimento all'istanza e non la copia .


5
+1 per "Se assegni un'istanza della classe a un'altra variabile, conterrà solo il riferimento dell'istanza che non verrà copiato."
Saif,

8

Le risposte sopra sono corrette Spero che la mia risposta possa aiutare qualcuno che non capisce le risposte sopra.

Bene in Swift Esistono due tipi di oggetti

  1. struct
  2. Classe

La principale differenza tra loro è

  • Struct è il tipo di valore
  • La classe è il tipo di riferimento

Ad esempio qui codice per capire bene.

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

Questa era la differenza principale, ma abbiamo anche delle differenze secondarie.

Classe

  1. Deve dichiarare l'inizializzatore (costruttore)
  2. Ha deinizializzatori
  3. Può ereditare da altre classi

struct

  1. Ha un inizializzatore gratuito per te, non devi dichiarare l'inizializzatore se lo fai l'inizializzatore gratuito verrà sovrascritto dal tuo inizializzatore dichiarato
  2. Non avere deinizializzatore
  3. Impossibile ereditare da altra struttura

7

Questa domanda sembra essere duplicata ma a prescindere, quanto segue risponderebbe alla maggior parte del caso d'uso:

  1. Una delle differenze più importanti tra strutture e classi è che le strutture sono tipi di valore e vengono sempre copiate quando vengono passate nel codice e le classi sono di tipo di riferimento e passano per riferimento.

  2. Inoltre, le classi hanno Eredità che consente a una classe di ereditare le caratteristiche di un'altra.

  3. Le proprietà di Struct sono archiviate su Stack e le istanze di Classe sono archiviate su Heap, quindi a volte lo stack è drasticamente più veloce di una classe.

  4. Struct ottiene automaticamente un inizializzatore predefinito, mentre in Class dobbiamo inizializzare.

  5. Struct è thread-safe o singleton in qualsiasi momento.

Inoltre, per riassumere la differenza tra strutture e classi, è necessario comprendere la differenza tra valore e tipi di riferimento.

  1. Quando si effettua una copia di un tipo di valore, copia tutti i dati dall'oggetto che si sta copiando nella nuova variabile. Sono 2 cose separate e cambiando l'una non influisce sull'altra.
  2. Quando si effettua una copia di un tipo di riferimento, la nuova variabile si riferisce alla stessa posizione di memoria della cosa che si sta copiando. Ciò significa che cambiando l'uno cambierà l'altro poiché entrambi si riferiscono alla stessa posizione di memoria. Il seguente codice di esempio potrebbe essere preso come riferimento.

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

Produzione:

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

Ciao Dilip, puoi fare un esempio per "Struct è thread safe o singleton in qualsiasi momento." ?. Grazie in anticipo.
Narasimha Nallamsetty

3

Se guardi più lontano nel manuale di Apple vedrai questa sezione: "Le strutture e le enumerazioni sono tipi di valore"

In questa sezione vedrai questo:

“Let hd = Risoluzione (larghezza: 1920, altezza: 1080) var cinema = hd Questo esempio dichiara una costante chiamata hd e la imposta su una risoluzione istanza inizializzata con la larghezza e l'altezza del video Full HD (1920 pixel di larghezza per 1080 pixel di altezza).

Dichiara quindi una variabile chiamata cinema e la imposta sul valore corrente di hd. Poiché la risoluzione è una struttura, viene creata una copia dell'istanza esistente e questa nuova copia viene assegnata al cinema. Anche se hd e cinema ora hanno la stessa larghezza e altezza, sono due casi completamente diversi dietro le quinte.

Successivamente, la proprietà width del cinema viene modificata per essere la larghezza dello standard 2K leggermente più ampio utilizzato per la proiezione del cinema digitale (2048 pixel di larghezza e 1080 pixel di altezza):

Cinema larghezza = 2048 Il controllo della proprietà larghezza del cinema mostra che è effettivamente cambiato in 2048:

Println ("adesso il cinema è (larghezza del cinema.) Pixel pixel") // stampe "adesso il cinema è largo 2048 pixel Tuttavia, la proprietà width dell'istanza hd originale ha ancora il vecchio valore del 1920:

println ("hd è ancora (larghezza hd.) pixel di larghezza") // stampe "hd è ancora 1920 pixel di larghezza"

Quando al cinema è stato assegnato il valore corrente di hd, i valori memorizzati in hd sono stati copiati nella nuova istanza cinematografica. Il risultato finale sono due istanze completamente separate, che contengono appena gli stessi valori numerici. Poiché sono istanze separate, l'impostazione della larghezza del cinema su 2048 non influisce sulla larghezza memorizzata in hd. "

Estratto da: Apple Inc. "The Swift Programming Language". iBook. https://itun.es/us/jEUH0.l

Questa è la più grande differenza tra le strutture e le classi. Le strutture vengono copiate e le classi vengono referenziate.


1

Di solito (nella maggior parte dei linguaggi di programmazione), gli oggetti sono blocchi di dati che sono memorizzati sull'heap e quindi un riferimento (normalmente un puntatore) a questi blocchi, contiene un name sta usando per accedere a questi blocchi di dati. Questo meccanismo consente di condividere oggetti nell'heap copiando il valore dei loro riferimenti (puntatori). Questo non è il caso di tipi di dati di base come Integer, ed è perché la memoria necessaria per creare un riferimento è quasi uguale all'oggetto (in questo caso il valore intero). Pertanto, verranno passati come valori e non come riferimento nel caso di oggetti di grandi dimensioni.

Swift usa struct per migliorare le prestazioni anche con oggetti String e Array.

Una lettura davvero buona qui


1

Per comprendere la differenza tra le strutture e le classi, dobbiamo conoscere la differenza principale tra valore e tipi di riferimento. Le strutture sono tipi di valore e ciò significa che ogni cambiamento su di esse modificherà quel valore, le classi sono tipi di riferimento e ogni cambiamento in un tipo di riferimento modificherà il valore allocato in quel luogo di memoria o riferimento. Per esempio:

Cominciamo con una classe, questa classe è conforme a Equatable solo per poter confrontare istanze, creiamo un'istanza chiamata pointClassInstanceAe altre chiamate pointClassInstanceBassegniamo la classe A alla classe B, ora l'asserzione dice che sono uguali ...

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

Ok, cosa è successo qui perché se abbiamo appena cambiato il valore x di pointsClassInstanceB, ha cambiato anche il valore x di pointClassInstanceA? bene, questo mostra come funzionano i tipi di riferimento, quando assegniamo l'istanza A, come valore dell'istanza B e poi modifichiamo X di uno di essi cambierà entrambi gli X perché condividono lo stesso riferimento e ciò che è cambiato è stato il valore di quello riferimento.

Facciamo lo stesso ma con una struttura

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

Abbiamo sostanzialmente la stessa struttura della nostra classe, ma ora puoi vedere che quando stampi il valore x di pointStructInstanceA questo caso non è cambiato, e questo perché i tipi di valore funzionano in modo diverso e ogni modifica su una delle loro istanze sarà " indipendente "e non influirà sull'altro.

Swift suggerisce di usare più tipi di valore e puoi dire che le loro librerie sono basate su strutture per evitare i problemi che portano i tipi di riferimento, come modificare involontariamente un valore ecc. Le strutture sono la strada da percorrere su Swift. Spero che sia d'aiuto.


1

Ecco un esempio che mostra esattamente la differenza tra struct e class.

screenshot del codice scritto nel parco giochi
screenshot del codice scritto nel parco giochi

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

Tipi rapidi

Value type è un tipo il cui valore viene copiato quando viene assegnato a una variabile o costante o quando viene passato a una funzione

Reference types non vengono copiati quando vengono assegnati a una variabile o costante o quando vengono passati a una funzione

Tipo valore :
Struct, Enum, Tuple
struct String, struct Array( Set, Dictionary)

  • Quando si assegna o si passa viene creata value typeuna nuova copia dei dati. In realtà il meccanismo copy on write- COWviene utilizzato con alcune ottimizzazioni, ad esempio la copia viene creata quando l'oggetto viene modificato
  • Quando modifichi un'istanza ha solo locale effetto .
  • La Memoria impilamento viene utilizzato.

Tipo di riferimento :
Class,Function

  • Quando si assegna o si passa reference typeun nuovo riferimento all'istanza originale verrà creato (l'indirizzo dell'istanza viene copiato).
  • Quando si modifica un'istanza ha un effetto globale perché l'istanza è condivisa e accessibile da qualsiasi riferimento che punti su di essa.
  • La memoria heap viene utilizzato.

inserisci qui la descrizione dell'immagine

Value typesi consiglia di utilizzare per impostazione predefinita . Il più grande vantaggio Value typeè che di solito lo sonothread safe

Reference type Professionisti:

  • possono essere ereditati,
  • deinit() può essere utilizzato,
  • confrontare le istanze per riferimento ===,
  • Objective-Cinteroperabilità perché è Value Typestata introdotta in Swift.

[let vs var, class vs struct]
Scelta tra strutture e
tipi di
classi Classi e strutture


0

Alreday c'è molto scritto su questo, vorrei aggiungere un'analogia lì. Spero che non avrai mai avuto dubbi in mente dopo: Linea di fondo: le classi vengono passate per riferimento mentre le strutture vengono passate per valore.

Supponi di condividere un foglio di documenti Google con il tuo amico. Ora se cambia qualcosa in questo, vedrai anche che le modifiche sul tuo documento Google, significa che anche la tua copia è interessata. Questo è fondamentalmente " passato per riferimento ".

Ma supponiamo, se hai un .XLS salvato nella tua macchina. Fornisci quel file da dare al tuo amico. Ora, se sta apportando delle modifiche a quel file, il tuo file non sarà incasinato / effettuato perché hai la tua copia. Questo è fondamentalmente " passato per valore ". Esistono già molti programmi semplici per verificare questa analogia in rapidi campi da gioco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.