Tại sao chọn Struct Over Class?

491
bluedevil2k 2014-06-16 08:33.

Chơi với Swift, đến từ nền tảng Java, tại sao bạn lại muốn chọn Struct thay vì Class? Có vẻ như chúng giống nhau, với một cấu trúc cung cấp ít chức năng hơn. Tại sao lại chọn nó?

15 answers

566
drewag 2014-06-16 08:37.

Theo cuộc trò chuyện rất phổ biến WWDC 2015 Lập trình hướng giao thức bằng Swift ( video , bản ghi ), Swift cung cấp một số tính năng giúp cấu trúc tốt hơn các lớp trong nhiều trường hợp.

Các cấu trúc được ưu tiên hơn nếu chúng tương đối nhỏ và có thể sao chép được vì sao chép sẽ an toàn hơn so với việc có nhiều tham chiếu đến cùng một trường hợp như xảy ra với các lớp. Điều này đặc biệt quan trọng khi truyền xung quanh một biến cho nhiều lớp và / hoặc trong môi trường đa luồng. Nếu bạn luôn có thể gửi một bản sao biến của mình đến những nơi khác, bạn sẽ không bao giờ phải lo lắng về việc nơi khác thay đổi giá trị của biến bên dưới bạn.

Với Structs, không cần phải lo lắng về việc rò rỉ bộ nhớ hoặc nhiều luồng chạy đua để truy cập / sửa đổi một phiên bản duy nhất của một biến. (Đối với những người có đầu óc kỹ thuật hơn, ngoại lệ đối với điều đó là khi nắm bắt một cấu trúc bên trong một bao đóng bởi vì sau đó nó thực sự đang nắm bắt một tham chiếu đến cá thể trừ khi bạn đánh dấu rõ ràng nó là được sao chép).

Các lớp cũng có thể trở nên cồng kềnh vì một lớp chỉ có thể kế thừa từ một lớp cha duy nhất. Điều đó khuyến khích chúng tôi tạo ra các siêu lớp khổng lồ bao gồm nhiều khả năng khác nhau chỉ có liên quan lỏng lẻo. Việc sử dụng các giao thức, đặc biệt là với các phần mở rộng giao thức nơi bạn có thể cung cấp các triển khai cho các giao thức, cho phép bạn loại bỏ nhu cầu về các lớp để đạt được loại hành vi này.

Bài nói chuyện đưa ra các tình huống sau đây trong đó các lớp học được ưu tiên:

  • Sao chép hoặc so sánh các phiên bản không có ý nghĩa (ví dụ: Window)
  • Thời gian tồn tại của phiên bản được gắn với các tác động bên ngoài (ví dụ: TemporaryFile)
  • Các phiên bản chỉ là "phần chìm" - ống dẫn chỉ ghi sang trạng thái bên ngoài (ví dụ :CGContext)

Nó ngụ ý rằng các cấu trúc nên là mặc định và các lớp phải là một dự phòng.

Mặt khác, tài liệu Ngôn ngữ lập trình Swift hơi mâu thuẫn:

Các cá thể cấu trúc luôn được chuyển bằng giá trị và các cá thể lớp luôn được chuyển bằng tham chiếu. Điều này có nghĩa là chúng phù hợp với các loại nhiệm vụ khác nhau. Khi bạn xem xét các cấu trúc dữ liệu và chức năng mà bạn cần cho một dự án, hãy quyết định xem mỗi cấu trúc dữ liệu nên được định nghĩa là một lớp hay là một cấu trúc.

Theo nguyên tắc chung, hãy cân nhắc tạo cấu trúc khi áp dụng một hoặc nhiều điều kiện sau:

  • Mục đích chính của cấu trúc là đóng gói một vài giá trị dữ liệu tương đối đơn giản.
  • Điều hợp lý là mong đợi rằng các giá trị được đóng gói sẽ được sao chép thay vì được tham chiếu khi bạn gán hoặc chuyển xung quanh một phiên bản của cấu trúc đó.
  • Bất kỳ thuộc tính nào được lưu trữ bởi cấu trúc đều là các kiểu giá trị, chúng cũng sẽ được sao chép thay vì được tham chiếu.
  • Cấu trúc không cần kế thừa các thuộc tính hoặc hành vi từ một kiểu hiện có khác.

Ví dụ về các ứng cử viên tốt cho cấu trúc bao gồm:

  • Kích thước của một hình dạng hình học, có lẽ bao gồm thuộc tính width và thuộc tính height, cả hai đều thuộc loại Double.
  • Một cách để tham chiếu đến các phạm vi trong một chuỗi, có thể đóng gói thuộc tính start và thuộc tính length, cả hai đều thuộc loại Int.
  • Một điểm trong hệ tọa độ 3D, có lẽ bao gồm các thuộc tính x, y và z, mỗi thuộc tính Double.

Trong tất cả các trường hợp khác, hãy xác định một lớp và tạo các thể hiện của lớp đó để được quản lý và chuyển qua tham chiếu. Trong thực tế, điều này có nghĩa là hầu hết các cấu trúc dữ liệu tùy chỉnh phải là các lớp, không phải cấu trúc.

Ở đây nó tuyên bố rằng chúng ta nên mặc định sử dụng các lớp và chỉ sử dụng cấu trúc trong các trường hợp cụ thể. Cuối cùng, bạn cần hiểu ý nghĩa thế giới thực của các loại giá trị so với các loại tham chiếu và sau đó bạn có thể đưa ra quyết định sáng suốt về thời điểm sử dụng cấu trúc hoặc lớp. Ngoài ra, hãy nhớ rằng những khái niệm này luôn phát triển và tài liệu Ngôn ngữ lập trình Swift đã được viết trước khi buổi nói chuyện về Lập trình hướng giao thức được đưa ra.

167
Khanh Nguyen 2014-06-17 02:22.

Vì các cá thể cấu trúc được phân bổ trên ngăn xếp và các cá thể lớp được cấp phát trên heap, nên các cấu trúc đôi khi có thể nhanh hơn đáng kể.

Tuy nhiên, bạn nên luôn tự đo lường và quyết định dựa trên trường hợp sử dụng duy nhất của mình.

Xem xét ví dụ sau đây, mà thể hiện 2 chiến lược của gói Intkiểu dữ liệu sử dụng structclass. Tôi đang sử dụng 10 giá trị lặp lại để phản ánh tốt hơn thế giới thực, nơi bạn có nhiều trường.

class Int10Class {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

struct Int10Struct {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

func + (x: Int10Class, y: Int10Class) -> Int10Class {
    return IntClass(x.value + y.value)
}

func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
    return IntStruct(x.value + y.value)
}

Hiệu suất được đo bằng cách sử dụng

// Measure Int10Class
measure("class (10 fields)") {
    var x = Int10Class(0)
    for _ in 1...10000000 {
        x = x + Int10Class(1)
    }
}

// Measure Int10Struct
measure("struct (10 fields)") {
    var y = Int10Struct(0)
    for _ in 1...10000000 {
        y = y + Int10Struct(1)
    }
}

func measure(name: String, @noescape block: () -> ()) {
    let t0 = CACurrentMediaTime()

    block()

    let dt = CACurrentMediaTime() - t0
    print("\(name) -> \(dt)")
}

Bạn có thể tìm thấy mã tại https://github.com/knguyen2708/StructVsClassPerformance

CẬP NHẬT (27/03/2018) :

Kể từ Swift 4.0, Xcode 9.2, đang chạy bản phát hành trên iPhone 6S, iOS 11.2.6, cài đặt Swift Compiler là -O -whole-module-optimization:

  • class phiên bản mất 2,06 giây
  • struct phiên bản mất 4,17e-08 giây (nhanh hơn 50.000.000 lần)

(Tôi không còn trung bình nhiều lần chạy nữa, vì sự khác biệt rất nhỏ, dưới 5%)

Lưu ý : sự khác biệt sẽ ít kịch tính hơn rất nhiều nếu không có tối ưu hóa toàn bộ mô-đun. Tôi rất vui nếu ai đó có thể chỉ ra lá cờ thực sự làm gì.


CẬP NHẬT (ngày 7 tháng 5 năm 2016) :

Kể từ Swift 2.2.1, Xcode 7.3, chạy phiên bản phát hành trên iPhone 6S, iOS 9.3.1, trung bình trong 5 lần chạy, cài đặt Swift Compiler là -O -whole-module-optimization:

  • class phiên bản mất 2.159942142s
  • struct phiên bản mất 5,83E-08s (nhanh hơn 37.000.000 lần)

Lưu ý : như ai đó đã đề cập rằng trong các tình huống thực tế, có thể sẽ có nhiều hơn 1 trường trong một cấu trúc, tôi đã thêm các bài kiểm tra cho cấu trúc / lớp với 10 trường thay vì 1. Đáng ngạc nhiên là kết quả không thay đổi nhiều.


KẾT QUẢ GỐC (ngày 1 tháng 6 năm 2014):

(Chạy trên struct / class với 1 trường, không phải 10)

Kể từ Swift 1.2, Xcode 6.3.2, chạy bản phát hành trên iPhone 5S, iOS 8.3, trung bình trong 5 lần chạy

  • class phiên bản mất 9,788332333s
  • struct phiên bản mất 0,010532942 giây (nhanh hơn 900 lần)

KẾT QUẢ CŨ (từ thời điểm không xác định)

(Chạy trên struct / class với 1 trường, không phải 10)

Với phiên bản phát hành trên MacBook Pro của tôi:

  • Các classphiên bản mất 1,10082 giây
  • Các structphiên bản mất 0,02324 giây (50 lần nhanh hơn)
60
MadNik 2015-03-04 14:03.

Điểm giống nhau giữa cấu trúc và lớp.

Tôi đã tạo ý chính cho điều này với các ví dụ đơn giản. https://github.com/objc-swift/swift-classes-vs-structures

Và sự khác biệt

1. Tính kế thừa.

cấu trúc không thể kế thừa nhanh chóng. Nếu bạn muốn

class Vehicle{
}

class Car : Vehicle{
}

Tham gia một lớp học.

2. Đi qua

Các cấu trúc Swift chuyển theo giá trị và các thể hiện của lớp truyền theo tham chiếu.

Sự khác biệt theo ngữ cảnh

Cấu trúc hằng và biến

Ví dụ (Được sử dụng tại WWDC 2014)

struct Point{
 
   var x = 0.0;
   var y = 0.0;

} 

Định nghĩa một cấu trúc được gọi là Point.

var point = Point(x:0.0,y:2.0)

Bây giờ nếu tôi cố gắng thay đổi x. Đó là một biểu thức hợp lệ.

point.x = 5

Nhưng nếu tôi định nghĩa một điểm là hằng số.

let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.

Trong trường hợp này, toàn bộ điểm là hằng số bất biến.

Nếu tôi đã sử dụng một lớp Point để thay thế thì đây là một biểu thức hợp lệ. Bởi vì trong một hằng số không thay đổi của lớp là tham chiếu đến bản thân lớp chứ không phải là các biến thể hiện của nó (Trừ khi các biến đó được định nghĩa là hằng số)

29
Honey 2016-06-25 16:12.

Giả sử rằng chúng ta biết Struct là một kiểu giá trịClass là một kiểu tham chiếu .

Nếu bạn không biết kiểu giá trị và kiểu tham chiếu là thì hãy xem Sự khác biệt giữa chuyển theo tham chiếu so với chuyển theo giá trị là gì?

Dựa trên bài đăng của mikeash :

... Hãy xem xét một số ví dụ rõ ràng, cực đoan trước. Số nguyên rõ ràng có thể sao chép được. Chúng phải là các loại giá trị. Không thể sao chép hợp lý các ổ cắm mạng. Chúng phải là loại tham chiếu. Các điểm, như trong cặp x, y, có thể sao chép được. Chúng phải là các loại giá trị. Không thể sao chép hợp lý một bộ điều khiển đại diện cho đĩa. Đó phải là một loại tham chiếu.

Một số loại có thể được sao chép nhưng nó có thể không phải là điều bạn muốn xảy ra mọi lúc. Điều này cho thấy rằng chúng nên là loại tham chiếu. Ví dụ, một nút trên màn hình có thể được sao chép về mặt khái niệm. Bản sao sẽ không hoàn toàn giống với bản gốc. Một cú nhấp chuột vào bản sao sẽ không kích hoạt bản gốc. Bản sao sẽ không chiếm cùng một vị trí trên màn hình. Nếu bạn chuyển nút xung quanh hoặc đặt nó vào một biến mới, có thể bạn sẽ muốn tham chiếu đến nút gốc và bạn chỉ muốn tạo một bản sao khi nó được yêu cầu rõ ràng. Điều đó có nghĩa là loại nút của bạn phải là loại tham chiếu.

Bộ điều khiển chế độ xem và cửa sổ là một ví dụ tương tự. Chúng có thể sao chép được, có thể tưởng tượng được, nhưng hầu như không bao giờ là những gì bạn muốn làm. Chúng phải là loại tham chiếu.

Còn các loại mô hình thì sao? Bạn có thể có kiểu Người dùng đại diện cho người dùng trên hệ thống của mình hoặc kiểu Tội phạm đại diện cho hành động do Người dùng thực hiện. Đây là những loại khá dễ sao chép, vì vậy chúng có lẽ nên là các loại giá trị. Tuy nhiên, bạn có thể muốn các cập nhật về Tội phạm của người dùng được thực hiện ở một nơi trong chương trình của bạn để hiển thị cho các phần khác của chương trình. Điều này cho thấy rằng Người dùng của bạn nên được quản lý bởi một số loại bộ điều khiển người dùng sẽ là một loại tham chiếu . ví dụ

struct User {}
class UserController {
    var users: [User]

    func add(user: User) { ... }
    func remove(userNamed: String) { ... }
    func ...
}

Bộ sưu tập là một trường hợp thú vị. Chúng bao gồm những thứ như mảng và từ điển, cũng như chuỗi. Chúng có thể sao chép được không? Chắc chắn. Việc sao chép nội dung bạn muốn có diễn ra dễ dàng và thường xuyên không? Điều đó ít rõ ràng hơn.

Hầu hết các ngôn ngữ nói "không" với điều này và đặt các loại tham chiếu bộ sưu tập của họ. Điều này đúng trong Objective-C và Java và Python và JavaScript và hầu hết mọi ngôn ngữ khác mà tôi có thể nghĩ đến. (Một ngoại lệ chính là C ++ với các kiểu tập hợp STL, nhưng C ++ là kẻ điên cuồng của thế giới ngôn ngữ làm mọi thứ kỳ lạ.)

Swift nói "có", có nghĩa là các kiểu như Mảng và Từ điển và Chuỗi là cấu trúc chứ không phải là lớp. Chúng được sao chép khi chuyển nhượng và chuyển chúng dưới dạng tham số. Đây là một lựa chọn hoàn toàn hợp lý miễn là bản sao rẻ, điều mà Swift rất cố gắng để đạt được. ...

Cá nhân tôi không đặt tên cho các lớp của mình như vậy. Tôi thường đặt tên là UserManager của tôi thay vì UserController nhưng ý tưởng vẫn giống nhau

Ngoài ra, không sử dụng lớp khi bạn phải ghi đè từng và mọi trường hợp của một hàm tức là chúng không có bất kỳ chức năng được chia sẻ nào .

Vì vậy, thay vì có một số lớp con của một lớp. Sử dụng một số cấu trúc phù hợp với một giao thức.


Một trường hợp hợp lý khác đối với cấu trúc là khi bạn muốn tạo delta / diff của mô hình cũ và mới. Với các loại tham chiếu, bạn không thể làm điều đó ngay lập tức. Với loại giá trị, các đột biến không được chia sẻ.

28
Dan Rosenstark 2015-01-17 12:09.

Dưới đây là một số lý do khác để xem xét:

  1. structs nhận được một trình khởi tạo tự động mà bạn không phải duy trì trong mã.

    struct MorphProperty {
       var type : MorphPropertyValueType
       var key : String
       var value : AnyObject
    
       enum MorphPropertyValueType {
           case String, Int, Double
       }
     }
    
     var m = MorphProperty(type: .Int, key: "what", value: "blah")
    

Để có được điều này trong một lớp, bạn sẽ phải thêm trình khởi tạo và duy trì trình intializer ...

  1. Các loại tập hợp cơ bản như Arraylà cấu trúc. Bạn càng sử dụng chúng trong mã của riêng mình, bạn sẽ càng quen với việc chuyển theo giá trị thay vì tham chiếu. Ví dụ:

    func removeLast(var array:[String]) {
       array.removeLast()
       println(array) // [one, two]
    }
    
    var someArray = ["one", "two", "three"]
    removeLast(someArray)
    println(someArray) // [one, two, three]
    
  2. Rõ ràng tính bất biến so với khả năng thay đổi là một chủ đề lớn, nhưng rất nhiều người thông minh nghĩ rằng tính bất biến - cấu trúc trong trường hợp này - thích hợp hơn. Đối tượng có thể thay đổi và bất biến

19
Catfish_Man 2014-06-16 08:38.

Một số ưu điểm:

  • tự động an toàn luồng do không thể chia sẻ
  • sử dụng ít bộ nhớ hơn do không có isa và refcount (và trên thực tế, nói chung là ngăn xếp được cấp phát)
  • các phương thức luôn được gửi tĩnh, vì vậy có thể được nội tuyến (mặc dù @final có thể làm điều này cho các lớp)
  • dễ lý giải hơn (không cần phải "sao chép bảo vệ" như thông thường với NSArray, NSString, v.v.) vì lý do tương tự như an toàn luồng
12
Manoj Karki 2016-05-11 02:25.

Cấu trúc nhanh hơn nhiều so với Class. Ngoài ra, nếu bạn cần kế thừa thì bạn phải sử dụng Class. Điểm quan trọng nhất là Class là kiểu tham chiếu trong khi Structure là kiểu giá trị. ví dụ,

class Flight {
    var id:Int?
    var description:String?
    var destination:String?
    var airlines:String?
    init(){
        id = 100
        description = "first ever flight of Virgin Airlines"
        destination = "london"
        airlines = "Virgin Airlines"
    } 
}

struct Flight2 {
    var id:Int
    var description:String
    var destination:String
    var airlines:String  
}

bây giờ hãy tạo phiên bản của cả hai.

var flightA = Flight()

var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )

bây giờ cho phép chuyển phiên bản này cho hai hàm sửa đổi id, mô tả, đích, v.v.

func modifyFlight(flight:Flight) -> Void {
    flight.id = 200
    flight.description = "second flight of Virgin Airlines"
    flight.destination = "new york"
    flight.airlines = "Virgin Airlines"
}

cũng thế,

func modifyFlight2(flight2: Flight2) -> Void {
    var passedFlight = flight2
    passedFlight.id = 200
    passedFlight.description = "second flight from virgin airlines" 
}

vì thế,

modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)

bây giờ nếu chúng tôi in id và mô tả của FlightA, chúng tôi nhận được

id = 200
description = "second flight of Virgin Airlines"

Ở đây, chúng ta có thể thấy id và mô tả của FlightA đã được thay đổi vì tham số được truyền cho phương thức sửa đổi thực sự trỏ đến địa chỉ bộ nhớ của đối tượng FlightA (kiểu tham chiếu).

bây giờ nếu chúng tôi in id và mô tả của phiên bản FLightB mà chúng tôi nhận được,

id = 100
description = "first ever flight of Virgin Airlines"

Ở đây chúng ta có thể thấy rằng cá thể FlightB không bị thay đổi bởi vì trong phương thức ModFlight2, cá thể thực tế của Flight2 được chuyển hơn là tham chiếu (kiểu giá trị).

12
casillas 2018-12-04 11:14.

Structsđã value typeClassesđangreference type

  • Loại giá trị nhanh hơn loại Tham chiếu
  • Các cá thể kiểu giá trị an toàn trong môi trường đa luồng vì nhiều luồng có thể thay đổi thể hiện mà không phải lo lắng về điều kiện chủng tộc hoặc bế tắc
  • Loại giá trị không có tham chiếu không giống như loại tham chiếu; do đó không có rò rỉ bộ nhớ.

Sử dụng một valueloại khi:

  • Bạn muốn các bản sao có trạng thái độc lập, dữ liệu sẽ được sử dụng trong mã trên nhiều chuỗi

Sử dụng một referenceloại khi:

  • Bạn muốn tạo trạng thái chia sẻ, có thể thay đổi.

Thông tin thêm cũng có thể được tìm thấy trong tài liệu của Apple

https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html


thông tin thêm

Các kiểu giá trị Swift được giữ trong ngăn xếp. Trong một quy trình, mỗi luồng có không gian ngăn xếp riêng, vì vậy không luồng nào khác có thể truy cập trực tiếp vào loại giá trị của bạn. Do đó không có điều kiện cuộc đua, khóa, bế tắc hoặc bất kỳ sự phức tạp đồng bộ hóa luồng liên quan nào.

Các kiểu giá trị không cần cấp phát bộ nhớ động hoặc đếm tham chiếu, cả hai đều là các phép toán đắt tiền. Đồng thời, các phương thức trên các kiểu giá trị được gửi tĩnh. Những điều này tạo ra một lợi thế rất lớn trong việc ủng hộ các loại giá trị về mặt hiệu suất.

Xin nhắc lại đây là danh sách Swift

Các loại giá trị:

  • Cấu trúc
  • Enum
  • Tuple
  • Nguyên thủy (Int, Double, Bool, v.v.)
  • Bộ sưu tập (Mảng, Chuỗi, Từ điển, Tập hợp)

Các loại tham khảo:

  • Lớp học
  • Mọi thứ đến từ NSObject
  • Chức năng
  • Khép kín
5
David James 2016-09-06 03:19.

Trả lời câu hỏi từ quan điểm của loại giá trị so với loại tham chiếu, từ bài đăng trên blog này của Apple, nó sẽ xuất hiện rất đơn giản:

Sử dụng kiểu giá trị [ví dụ: struct, enum] khi:

  • So sánh dữ liệu phiên bản với == có ý nghĩa
  • Bạn muốn các bản sao có trạng thái độc lập
  • Dữ liệu sẽ được sử dụng trong mã trên nhiều chuỗi

Sử dụng kiểu tham chiếu [ví dụ: lớp] khi:

  • So sánh danh tính cá thể với === có ý nghĩa
  • Bạn muốn tạo trạng thái chia sẻ, có thể thay đổi

Như đã đề cập trong bài viết đó, một lớp không có thuộc tính có thể ghi sẽ hoạt động giống hệt với một cấu trúc, với (tôi sẽ thêm) một lưu ý: cấu trúc là tốt nhất cho các mô hình an toàn luồng - một yêu cầu ngày càng sắp xảy ra trong kiến ​​trúc ứng dụng hiện đại.

3
Joride 2014-06-16 08:36.

Với các lớp bạn nhận được kế thừa và được truyền bằng tham chiếu, các cấu trúc không có tính kế thừa và được truyền theo giá trị.

Có những phiên WWDC tuyệt vời trên Swift, câu hỏi cụ thể này được trả lời chi tiết trong một trong số chúng. Hãy chắc chắn rằng bạn xem những thứ đó, vì nó sẽ giúp bạn tăng tốc nhanh hơn nhiều so với Hướng dẫn ngôn ngữ hoặc iBook.

2
yeoman 2016-06-15 23:06.

Tôi sẽ không nói rằng cấu trúc cung cấp ít chức năng hơn.

Chắc chắn, self là bất biến ngoại trừ một hàm đột biến, nhưng đó là về nó.

Kế thừa hoạt động tốt miễn là bạn bám vào ý tưởng cũ tốt rằng mọi lớp phải là trừu tượng hoặc cuối cùng.

Triển khai các lớp trừu tượng dưới dạng giao thức và các lớp cuối cùng dưới dạng cấu trúc.

Điều thú vị về cấu trúc là bạn có thể làm cho các trường của mình có thể thay đổi mà không cần tạo trạng thái có thể thay đổi được chia sẻ bởi vì sao chép khi ghi sẽ xử lý điều đó :)

Đó là lý do tại sao các thuộc tính / trường trong ví dụ sau đây đều có thể thay đổi được, điều này tôi sẽ không làm trong Java hoặc C # hoặc các lớp swift .

Cấu trúc kế thừa mẫu với một chút cách sử dụng đơn giản và bẩn thỉu ở dưới cùng trong hàm có tên "example":

protocol EventVisitor
{
    func visit(event: TimeEvent)
    func visit(event: StatusEvent)
}

protocol Event
{
    var ts: Int64 { get set }

    func accept(visitor: EventVisitor)
}

struct TimeEvent : Event
{
    var ts: Int64
    var time: Int64

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }
}

protocol StatusEventVisitor
{
    func visit(event: StatusLostStatusEvent)
    func visit(event: StatusChangedStatusEvent)
}

protocol StatusEvent : Event
{
    var deviceId: Int64 { get set }

    func accept(visitor: StatusEventVisitor)
}

struct StatusLostStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var reason: String

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

struct StatusChangedStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var newStatus: UInt32
    var oldStatus: UInt32

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

func readEvent(fd: Int) -> Event
{
    return TimeEvent(ts: 123, time: 56789)
}

func example()
{
    class Visitor : EventVisitor
    {
        var status: UInt32 = 3;

        func visit(event: TimeEvent)
        {
            print("A time event: \(event)")
        }

        func visit(event: StatusEvent)
        {
            print("A status event: \(event)")

            if let change = event as? StatusChangedStatusEvent
            {
                status = change.newStatus
            }
        }
    }

    let visitor = Visitor()

    readEvent(1).accept(visitor)

    print("status: \(visitor.status)")
}
2
Balasubramanian 2017-10-22 23:45.

Trong Swift, một mẫu lập trình mới đã được giới thiệu được gọi là Lập trình hướng giao thức.

Mẫu sáng tạo:

Trong nhanh chóng, Struct là một kiểu giá trị được sao chép tự động. Do đó, chúng tôi nhận được hành vi cần thiết để triển khai mẫu nguyên mẫu miễn phí.

Trong khi các lớp là kiểu tham chiếu, không được tự động sao chép trong quá trình gán. Để triển khai mẫu nguyên mẫu, các lớp phải áp dụng NSCopyinggiao thức.


Bản sao nông chỉ sao chép tham chiếu, trỏ đến các đối tượng đó trong khi bản sao sâu sao chép tham chiếu của đối tượng.


Thực hiện bản sao sâu cho mỗi loại tham chiếu đã trở thành một công việc tẻ nhạt. Nếu các lớp bao gồm thêm kiểu tham chiếu, chúng ta phải triển khai mẫu nguyên mẫu cho từng thuộc tính tham chiếu. Và sau đó chúng ta phải thực sự sao chép toàn bộ đồ thị đối tượng bằng cách triển khai NSCopyinggiao thức.

class Contact{
  var firstName:String
  var lastName:String
  var workAddress:Address // Reference type
}

class Address{
   var street:String
   ...
} 

Bằng cách sử dụng struct và enums , chúng tôi đã làm cho mã của mình đơn giản hơn vì chúng tôi không phải triển khai logic sao chép.

1
akshay 2016-11-18 01:17.

Nhiều API Cocoa yêu cầu các lớp con của NSObject, điều này buộc bạn phải sử dụng lớp. Nhưng ngoài ra, bạn có thể sử dụng các trường hợp sau từ blog Swift của Apple để quyết định sử dụng kiểu giá trị struct / enum hay kiểu tham chiếu lớp.

https://developer.apple.com/swift/blog/?id=10

0
johnbakers 2017-12-20 02:57.

Một điểm không nhận được sự chú ý trong những câu trả lời này là một biến giữ lớp so với một cấu trúc có thể lettrong một thời gian vẫn cho phép thay đổi các thuộc tính của đối tượng, trong khi bạn không thể làm điều này với một cấu trúc.

Điều này rất hữu ích nếu bạn không muốn biến trỏ tới một đối tượng khác, nhưng vẫn cần sửa đổi đối tượng, tức là trong trường hợp có nhiều biến cá thể mà bạn muốn cập nhật lần lượt. Nếu đó là một cấu trúc, bạn phải cho phép biến được đặt lại hoàn toàn thành một đối tượng khác bằng cách sử dụng varđể thực hiện việc này, vì kiểu giá trị không đổi trong Swift đúng cách cho phép không có đột biến, trong khi các kiểu (lớp) tham chiếu không hoạt động theo cách này.

0
Tapash Mollick 2018-05-24 02:35.

Vì struct là các kiểu giá trị và bạn có thể tạo bộ nhớ rất dễ dàng để lưu trữ vào ngăn xếp. Cấu trúc có thể dễ dàng truy cập và sau khi phạm vi công việc, nó dễ dàng được phân bổ từ bộ nhớ ngăn xếp thông qua cửa sổ bật lên từ đầu ngăn xếp. Mặt khác, lớp là một kiểu tham chiếu lưu trữ trong heap và những thay đổi được thực hiện trong một đối tượng lớp sẽ tác động đến đối tượng khác vì chúng được kết hợp chặt chẽ và là kiểu tham chiếu. Tất cả các thành viên của một cấu trúc là công khai trong khi tất cả các thành viên của một lớp là riêng tư .

Nhược điểm của struct là nó không thể được kế thừa.

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Một thương hiệu kế thừa khác có được cuộc sống mới khi những người chủ mới của Black Opal có được Hội chợ thời trang

Desiree Rogers, trái, và Cheryl Mayberry McKissack Chuyển sang, Fenty Beauty và Pat McGrath, có một đế chế làm đẹp mới do phụ nữ làm chủ đang trỗi dậy. Sau thương vụ mua lại mỹ phẩm Black Opal vào tháng 9, đội ngũ quyền lực của Giám đốc điều hành công ty Desiree Rogers và Chủ tịch Cheryl Mayberry McKissack đã thông báo mua lại thương hiệu làm đẹp tiên phong Fashion Fair từ người sáng lập Johnson Publishing Company (JPC).

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Ngoài việc trở nên vô nghĩa, các bên bộc lộ giới tính giờ đây đã trở nên chết người

Đối với những người có quá nhiều thời gian, tiệc tiết lộ giới tính là một cách thú vị để không cần áp đặt những định kiến ​​hạn chế lên thai nhi trước một đối tượng bạn bè giả vờ quan tâm một cách lịch sự. Tuy nhiên, việc chỉ dựa vào những chiếc bánh nướng có màu nhân tạo để biểu thị một tiếng hoo-ha hoặc một đứa trẻ đi tè đã trở nên xa xỉ trong các bậc cha mẹ trên Instagram.

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Kirstjen Nielsen đang cố gắng đổi mới bản thân với tư cách là một người phụ nữ 'nói ra sự thật cho sức mạnh'

Hôm thứ Tư, cựu Bộ trưởng An ninh Nội địa Kirstjen Nielsen vì một lý do nào đó đã được đưa ra một diễn đàn để phát biểu tại Hội nghị thượng đỉnh Những người phụ nữ quyền lực nhất của Fortune. Và có thể đoán trước được, người phụ nữ giám sát các nỗ lực (đang diễn ra) của chính quyền Trump nhằm chia cắt các gia đình ở biên giới đã sử dụng thời gian của mình như một cơ hội để tự bảo vệ mình và tự nhận mình là người — và hãy hít thở sâu ở đây — “đã nói sự thật với quyền lực.

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Toyota Racing Development sẽ cho ra mắt Supra 3000GT Concept, Massive Wing vào tháng tới

Vì thế hệ mới nhất của chiếc xe điều chỉnh được yêu thích trên thế giới hiện đã có mặt tại đây, nên chỉ có điều kiện là Toyota Racing Development sẽ đưa phiên bản Supra thế hệ thứ năm sửa đổi của riêng mình đến SEMA vào tháng tới. Toyota đã cho chúng tôi một gợi ý về những gì sẽ xảy ra trong tuần này: một chiếc Concept GR Supra 3000GT hiện đại.

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Thanh thiếu niên, Gia đình Florida Hội đồng quản trị trường học về Luật 'Không nói đồng tính': 'Buộc chúng tôi tự kiểm duyệt'

Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Khi bạn không thể trở thành người mà Internet muốn bạn trở thành

Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.

Language