cấu trúc vs lớp trong ngôn ngữ swift


192

Từ cuốn sách của Apple "Một trong những khác biệt quan trọng nhất giữa các cấu trúc và các lớp là các cấu trúc luôn được sao chép khi chúng được truyền xung quanh trong mã của bạn, nhưng các lớp được truyền qua tham chiếu."

Bất cứ ai có thể giúp tôi hiểu điều đó có nghĩa là gì? Đối với tôi, các lớp học và cấu trúc dường như giống nhau.


3
Xem sự khác biệt giữa struct và class trong .NET: stackoverflow.com/a/13275/19100 , tôi đoán rằng Swift sử dụng cùng một ngữ nghĩa.
dalle

23
@jonrsharpe có thể dễ dàng với bạn? bạn có thể cho tôi câu trả lời nếu bạn biết điều này
Manish Agrawal

1
Giá trị so với tham chiếu không phải là một khái niệm chỉ OOP. Nó ở đó trong C, như void my_func(int a)vs void my_func(int &a). Đây là một câu hỏi rất cơ bản của lập trình. Đọc thêm: stackoverflow.com/questions/373419/
Mạnh

Câu trả lời:


473

Đây là một ví dụ với a class. Lưu ý làm thế nào khi tên được thay đổi, thể hiện được tham chiếu bởi cả hai biến được cập nhật. Bobbây giờ Sue, ở mọi nơi Bobđã từng được tham khảo.

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"

Và bây giờ với một structgiá trị chúng ta thấy rằng các giá trị được sao chép và mỗi biến giữ cho nó các giá trị riêng. Khi chúng ta đặt tên thành Sue, Bobcấu trúc trong aStructkhông bị thay đổi.

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"

Vì vậy, để đại diện cho một thực thể phức tạp nhà nước, một classlà tuyệt vời. Nhưng đối với các giá trị chỉ đơn giản là phép đo hoặc bit của dữ liệu liên quan, structsẽ có ý nghĩa hơn để bạn có thể dễ dàng sao chép chúng xung quanh và tính toán với chúng hoặc sửa đổi các giá trị mà không sợ tác dụng phụ.


"Nhưng đối với các giá trị không phức tạp hơn chỉ đơn giản là một con số ..." Cảm ơn vì điều này Alex
Mike Rapadas

7
@MichaelRapadas Số thực sự cấu trúc trong Swift.
Nikolai Ruhe

Bạn có thể làm rõ điều aStruct and bStruct are two structs with the same value!này làm tôi bối rối vì các giá trị của các biến trong cấu trúc là khác nhau.
Julian Król

@ JulianKról Một dòng đó aStructbStructcó các giá trị giống hệt nhau. Cả hai đều có một nametrường duy nhất được đặt "Bob". Nhưng chúng là hai cấu trúc khác nhau. Điều này được chứng minh trên dòng tiếp theo khi bạn có thể thay đổi tên của một trong các cấu trúc và cái còn lại không thay đổi.
Alex Wayne

Chỉ cần bỏ lỡ nhiệm vụ. Đó là rõ ràng, cảm ơn. Có lẽ nó quá nóng ở bên ngoài :-)
Julian Król

60

Cả lớp và cấu trúc đều có thể làm:

  • Xác định các thuộc tính để lưu trữ giá trị
  • Xác định các phương thức để cung cấp chức năng
  • Gia tăng
  • Phù hợp với các giao thức
  • Xác định intialisers
  • Xác định đăng ký để cung cấp quyền truy cập vào các biến của họ

Chỉ có lớp mới có thể làm:

  • Di sản
  • Kiểu đúc
  • Xác định deinitialisers
  • Cho phép đếm tham chiếu cho nhiều tài liệu tham khảo.

32

structlà các loại giá trị. Điều đó có nghĩa là nếu bạn sao chép thể hiện của cấu trúc sang một biến khác, thì nó chỉ được sao chép vào biến đó.

Ví dụ cho loại giá trị

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

Các lớp học là loại tham khảo. Điều đó có nghĩa là nếu bạn gán một thể hiện của lớp cho một biến, nó sẽ chỉ giữ tham chiếu đến thể hiện đó chứ không giữ bản sao .


5
+1 cho "Nếu bạn gán một thể hiện của lớp cho một biến khác, nó sẽ chỉ giữ tham chiếu của thể hiện không sao chép."
Saif

8

Câu trả lời trên là chính xác Tôi hy vọng câu trả lời của tôi sẽ giúp những người không hiểu câu trả lời ở trên.

Vâng trong Swift Có hai loại đối tượng

  1. Cấu trúc
  2. Lớp học

Sự khác biệt chính giữa chúng là

  • Cấu trúc là giá trị loại
  • Lớp là kiểu tham chiếu

Ví dụ ở đây mã để hiểu rõ.

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

Đây là sự khác biệt chính nhưng chúng tôi cũng có sự khác biệt phụ.

Lớp học

  1. Phải khai báo trình khởi tạo (hàm tạo)
  2. Có deinitialisers
  3. Có thể kế thừa từ các lớp khác

Cấu trúc

  1. Nó có trình khởi tạo miễn phí cho bạn, bạn không phải khai báo initaliser nếu bạn làm trình khởi tạo miễn phí sẽ bị ghi đè bởi trình khởi tạo khai báo của bạn
  2. Không có deinitialiser
  3. Không thể kế thừa từ cấu trúc khác

7

Câu hỏi này có vẻ trùng lặp nhưng bất kể, câu hỏi nào sau đây sẽ trả lời hầu hết các trường hợp sử dụng:

  1. Một trong những khác biệt quan trọng nhất giữa các cấu trúc và các lớp là các cấu trúc là các loại giá trị và luôn được sao chép khi chúng được truyền xung quanh trong mã của bạn và các lớp là loại tham chiếu và được truyền bằng tham chiếu.

  2. Ngoài ra, các lớp có Kế thừa cho phép một lớp kế thừa các đặc điểm của lớp khác.

  3. Các thuộc tính cấu trúc được lưu trữ trên các thể hiện Stack và Class được lưu trữ trên Heap, do đó, đôi khi stack nhanh hơn một lớp.

  4. Struct sẽ tự động khởi tạo mặc định trong khi trong Class, chúng ta phải khởi tạo.

  5. Struct là chủ đề an toàn hoặc singleton tại bất kỳ thời điểm nào.

Ngoài ra, để tóm tắt sự khác biệt giữa các cấu trúc và các lớp, cần phải hiểu sự khác biệt giữa các loại giá trị và tham chiếu.

  1. Khi bạn tạo một bản sao của một loại giá trị, nó sẽ sao chép tất cả dữ liệu từ thứ bạn đang sao chép vào biến mới. Chúng là 2 thứ riêng biệt và thay đổi cái này không ảnh hưởng đến cái kia.
  2. Khi bạn tạo một bản sao của loại tham chiếu, biến mới đề cập đến cùng một vị trí bộ nhớ với thứ bạn đang sao chép. Điều này có nghĩa là việc thay đổi cái này sẽ thay đổi cái khác vì cả hai đều đề cập đến cùng một vị trí bộ nhớ. Mã mẫu dưới đây có thể được lấy làm tài liệu tham khảo.

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

Đầu ra:

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

Xin chào Dilip, bạn có thể đưa ra một ví dụ cho "Struct is thread safe or singleton tại bất kỳ thời điểm nào."?. Cảm ơn trước.
Narasimha Nallamsetty

3

Nếu bạn nhìn xa hơn trong cẩm nang táo, bạn sẽ thấy phần này: Cấu trúc và liệt kê là các loại giá trị

Trong phần này bạn sẽ thấy điều này:

Giảm cho hd = Độ phân giải (chiều rộng: 1920, chiều cao: 1080) var rạp chiếu phim = hd Ví dụ này khai báo một hằng số được gọi là hd và đặt nó thành Độ phân giải ví dụ được khởi tạo với chiều rộng và chiều cao của video full HD (rộng 1920 pixel cao 1080 pixel).

Sau đó, nó khai báo một biến gọi là rạp chiếu phim và đặt nó vào giá trị hiện tại của hd. Bởi vì Độ phân giải là một cấu trúc, một bản sao của thể hiện hiện tại được tạo ra và bản sao mới này được gán cho rạp chiếu phim. Mặc dù hd và rạp chiếu phim bây giờ có cùng chiều rộng và chiều cao, chúng là hai trường hợp hoàn toàn khác nhau đằng sau hậu trường.

Tiếp theo, thuộc tính chiều rộng của rạp chiếu phim được sửa đổi thành chiều rộng của tiêu chuẩn 2K rộng hơn một chút được sử dụng cho trình chiếu rạp chiếu phim kỹ thuật số (rộng 2048 pixel và cao 1080 pixel):

Rạp chiếu phim. Width = 2048 Kiểm tra thuộc tính chiều rộng của rạp chiếu phim cho thấy nó thực sự đã thay đổi thành 2048:

Println ("rạp chiếu phim bây giờ (rạp chiếu phim giá trị của năm 1920:

println ("hd vẫn (hd. width) pixel width") // print "hd vẫn rộng 1920 pixel

Khi rạp chiếu phim được đưa ra giá trị hiện tại của hd, các giá trị được lưu trữ trong hd đã được sao chép vào phiên bản rạp chiếu phim mới. Kết quả cuối cùng là hai trường hợp hoàn toàn riêng biệt, tình cờ có chứa các giá trị số giống nhau. Vì chúng là các trường hợp riêng biệt, việc đặt độ rộng của rạp chiếu phim thành 2048 không ảnh hưởng đến chiều rộng được lưu trữ trong hd.

Trích từ: Apple Inc., Ngôn ngữ lập trình Swift. Sách điện tử. https://itun.es/us/jEUH0.l

Đây là sự khác biệt lớn nhất giữa các cấu trúc và các lớp. Cấu trúc được sao chép và các lớp được tham chiếu.


1

Thông thường (trong hầu hết các ngôn ngữ lập trình), các đối tượng là các khối dữ liệu được lưu trữ trên heap và sau đó một tham chiếu (thường là một con trỏ) cho các khối này, chứa một name đang sử dụng để truy cập các khối dữ liệu này. Cơ chế này cho phép chia sẻ các đối tượng trong heap bằng cách sao chép giá trị của các tham chiếu (con trỏ) của chúng. Đây không phải là trường hợp của các kiểu dữ liệu cơ bản như Số nguyên và đó là do bộ nhớ cần thiết để tạo tham chiếu gần giống với đối tượng (trong trường hợp này là giá trị nguyên). Do đó, chúng sẽ được truyền dưới dạng các giá trị không phải là tham chiếu trong trường hợp các đối tượng lớn.

Swift sử dụng struct để cải thiện hiệu suất ngay cả với các đối tượng String và Array.

Một đọc thực sự tốt ở đây


1

Để hiểu được sự khác biệt giữa Structs và Classes, chúng ta cần biết sự khác biệt chính giữa các loại giá trị và tham chiếu. Cấu trúc là các loại giá trị và điều đó có nghĩa là mọi thay đổi trên chúng sẽ chỉ sửa đổi giá trị đó, Các lớp là các loại tham chiếu và mọi thay đổi trong loại tham chiếu sẽ sửa đổi giá trị được phân bổ ở vị trí của bộ nhớ hoặc tham chiếu. Ví dụ:

Chúng ta hãy bắt đầu với một Class, lớp này phù hợp với Equitable chỉ để có thể so sánh các thể hiện, chúng ta tạo một thể hiện được gọi pointClassInstanceAvà khác được gọi là pointClassInstanceBchúng ta gán lớp A cho lớp B, bây giờ khẳng định nói rằng chúng giống nhau ...

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, điều gì đã xảy ra ở đây tại sao nếu chúng ta chỉ thay đổi giá trị x của pointsClassInstanceB thì nó cũng thay đổi giá trị x của pointClassInstanceA? tốt, điều này cho thấy các kiểu tham chiếu hoạt động như thế nào, khi chúng ta gán thể hiện A, như một giá trị của thể hiện B và sau đó chúng ta sửa đổi X của một trong số chúng, nó sẽ thay đổi cả X vì chúng chia sẻ cùng một tham chiếu và giá trị của thay đổi đó là gì tài liệu tham khảo.

Chúng ta hãy làm tương tự nhưng với một cấu trúc

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

Về cơ bản, chúng tôi có cấu trúc giống như lớp của chúng tôi nhưng bây giờ bạn có thể thấy rằng khi bạn in giá trị x của pointStstallInstanceA thì trường hợp này không thay đổi và điều này là do các loại giá trị hoạt động khác nhau và mọi thay đổi trên một trong các trường hợp của chúng sẽ là " độc lập "và sẽ không ảnh hưởng đến người khác.

Swift đề nghị sử dụng nhiều loại giá trị hơn và bạn có thể nói rằng các thư viện của họ dựa trên các cấu trúc để tránh các vấn đề mà các loại tham chiếu mang lại, như vô tình sửa đổi một giá trị, v.v. Hy vọng nó giúp.


1

Dưới đây là một ví dụ cho thấy sự khác biệt chính xác giữa struct và class.

ảnh chụp màn hình mã viết trong sân chơi
ảnh chụp màn hình mã viết trong sân chơi

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

Các loại Swift

Value type là một loại có giá trị được sao chép khi nó được gán cho một biến hoặc hằng hoặc khi nó được truyền cho một hàm

Reference types không được sao chép khi chúng được gán cho một biến hoặc hằng hoặc khi chúng được truyền cho một hàm

Loại giá trị :
Struct, Enum, Tuple
struct String, struct Array( Set, Dictionary)

  • Khi bạn chỉ định hoặc vượt qua value type một bản sao dữ liệu mới được tạo. Trên thực tế, cơ chế copy on write- COWđược sử dụng với một số tối ưu hóa, ví dụ: bản sao được tạo khi đối tượng được sửa đổi
  • Khi bạn sửa đổi một thể hiện, nó chỉ có hiệu lực cục bộ .
  • Các bộ nhớ stack được sử dụng.

Loại tài liệu tham khảo :
Class,Function

  • Khi bạn gán hoặc chuyển reference typemột tham chiếu mới cho thể hiện ban đầu sẽ được tạo (địa chỉ của thể hiện được sao chép).
  • Khi bạn sửa đổi một thể hiện, nó có hiệu lực toàn cục vì thể hiện đó được chia sẻ và có thể truy cập bởi bất kỳ tham chiếu nào trỏ đến nó.
  • Các bộ nhớ Heap được sử dụng.

nhập mô tả hình ảnh ở đây

Value typeđược khuyến nghị sử dụng theo mặc định . Ưu điểm lớn nhất Value typelà thường làthread safe

Reference type Ưu điểm:

  • họ có thể được thừa kế,
  • deinit() có thể được sử dụng,
  • so sánh các trường hợp bằng cách tham chiếu ===,
  • Objective-Ckhả năng tương tác vì Value Typeđã được giới thiệu trong Swift.

[Tìm hiểu thêm về tính tương tác]
Lựa chọn giữa các cấu trúc và các lớp
Các loại Các
lớp và các cấu trúc


0

Alreday có rất nhiều bài viết về điều này, tôi muốn thêm một sự tương tự ở đó. Hy vọng bạn sẽ không bao giờ nghi ngờ gì về điều này sau: Dòng dưới cùng: các lớp được truyền bằng tham chiếu trong khi các cấu trúc được truyền theo giá trị.

Giả sử bạn đang chia sẻ một tài liệu google với bạn bè của bạn. Bây giờ nếu anh ta thay đổi bất cứ điều gì trong đó, bạn cũng sẽ thấy những thay đổi trên tài liệu google của bạn, có nghĩa là bản sao của bạn cũng bị ảnh hưởng. Điều đó về cơ bản là " thông qua tham chiếu ".

Nhưng giả sử, nếu bạn có một fie .XLS được lưu trong máy. Bạn cung cấp tập tin đó cho bạn của bạn. Bây giờ nếu anh ta thực hiện bất kỳ thay đổi nào trong tệp đó, tệp của bạn sẽ không bị rối / ảnh hưởng vì bạn có bản sao của riêng mình. Điều đó về cơ bản là " thông qua giá trị ". Bạn đã có nhiều chương trình đơn giản để kiểm tra sự tương tự này trong các sân chơi nhanh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.