So sánh class và struct swift

Chú ý: “Identical to” (===) có cùng nghĩa với so sanh “equal to” (==), bởi vì equal to (==) dùng để so sánh 2 giá trị của hằng số hay biến có bằng nhau hay không. Còn “Identical to” (===) là so sánh 2 tham chiếu của hằng số hoặc biến có trỏ đến cùng một địa chỉ hay không.

Class vs Struct là những kiểu cấu trúc cơ bản trong swift, cả 2 điều có các property và function. Nhưng chúng có những điểm chung và khác nhau, tuỳ vào mục đích sử dụng của bạn, để quản lí cấu trúc, bộ nhớ tốt hơn.

Những điểm chung giữa class vs struct :

+ Khai báo property để lưu trữ dữ liệu + Khái báo function + Dùng được subscript để truy cập dữ kiệu (arr[i],arr[i,j]…) + Định nghĩa khởi tạo + Mở rộng qua extension + Add protocol thêm vào để mở rộng chức năng

Những thứ class mà struct mà không có :

+ Class có thể thừa kế từ class khác + Cho phép kiểm tra và chuyển đổi loại của class (is, as) + Có hàm deinit(khi giải phóng bộ nhớ) để bạn sư dụng khi có nhu cầu + Kiểu tham chiếu (reference couting) cho phép nhiều hơn một lớp tham chiếu tới. Khi muốn so sánh các instance cùng tham chiếu tới 1 class được tạo ra hay không, ta có thể dùng (=== / !==)

Ví dụ ta khai báo class vs struct như sau :

class A { var id = “” var name = “” init(id:String,name:String) { self.id = id self.name = name } func printDes() { print(“(id)-(name)”) }}struct B { var id = “” var name = “” func printDes() { print(“(id)-(name)”) }}

Tính biến đổi thuộc tính (Mutability Property) : khi chúng ta khởi tạo 1 instance và với từ let thì class cho chúng ta thây đổi còn struct thì không, chúng ta phải sửa lại var của struct mới thay đổi được

Ví dụ :

let a = A(id: “1”, name: “Thang”) let b = B(id: “2”, name: “Hoa”) // Struct có sẵn hàm khởi tạo dự vào các propertya.id = “2” // Class thì cho phép b.id = “3” // struct không cho chúng ta thay đổi, mà bạn phải chuyển qua dùng*var* b = B(id: “2”, name: “Hoa”) b.id = “3”

Tính biến đổi hàm (Mutability Function ) : khi hàm trong struct của bạn có làm thấy đổi internal property thì phải phải thêm mutating phía trước function của bạn.

Struct và class là các cấu trúc linh hoạt, được sử dụng với nhiều mục đích khác nhau để trở thành các khối xây dựng chương trình của ban. Bạn định nghĩa các thuộc tính và phương thức để thêm vào các struct/class của bạn.

So sánh class và struct swift

So sánh class và struct swift
Cách khởi tạo 1 struc và 1 class khá giống nhau.

Điểm giống nhau giữa struct và class:

Struct và Class đều có thể:

  • Định nghĩa, khai báo các thuộc tính và hàm.
  • Khai báo subscripts.

class Rank {
    subscript (index: Int) -> String {
        switch index {
            case 1: return "First"
            case 2: return "Second"
            case 3: return "Three"
            default: return "Dont have rank"
        }
    }
}
let rank = Rank()
print (rank[1]) // -> "First"
print (rank[12]) // -> "Dont have rank"

  • Khai báo các initializers để khởi tạo.
  • Có thể mở rộng bằng extension.
  • Có thể implement các protocol để cung cấp các chức năng tiêu chuẩn.

Điểm khác nhau giữa Struct và Class:

Initialize:

Khi định nghĩa 1 class, bạn bắt buộc phải khởi tạo 1 hàm init cho các thuộc tính không phải optional hoặc chưa có giá trị default.

class Car {
    let id: Int = 1
    var color: UIColor?
    var price: Double
    init(price: Double) {
        self.price = price
    }
}
let car1 = Car(price: 5000)

Còn khi định nghĩa 1 struct, bạn không cần phải khởi tạo 1 hàm init bởi khi đó Struct đã tự định nghĩa 1 hàm init default cho bạn.

struct Car {
    let id: Int = 1
    var color: UIColor
    var price: Double
}
let car1 = Car(color: .red, price: 5000)

Tuy nhiên, nếu bạn khai báo thêm các init khác thì hàm init default của struct sẽ bị mất. Vì vậy, để tránh điều này, chỉ cần khai báo các hàm init mới ở extension thì hàm init default sẽ không bị mất.

So sánh class và struct swift

Struct là Value types còn Class là Reference types

Value type: 1 instance có kiểu là value type thì nó sẽ tự tạo ra các bản copy các giá trị của mình để truyền đi mỗi khi được nó đươc dùng để gán cho các instance khác, hoặc khi được dùng để truyền vào hàm. Bởi vậy, nếu bạn thay đổi giá trị các bản copy thì giá trị bản gốc cũng sẽ không bị thay đôi:

let car1 = Car(price: 5000)
var car2 = car1
car2.price = 10000
print(car1.price) // -> 5000.0
print(car2.price) // -> 10000.0

Reference type: Thay vì việc tạo ra các bản sao, thì 1 instance kiểu reference type sẽ tự truyền đi 1 tham chiếu tới chính nó khi được gán cho các insstance khác hoặc khi được truyền vào hàm.

let car1 = Car(price: 5000)
let car2 = car1
car2.price = 10000
print(car1.price) // -> 10000.0
print(car2.price) // -> 10000.0
print(car1 === car2) // -> true

Có thể hiểu đơn giản rằng, car1 sẽ tự gán chính bản thân nó cho car2 chứ không tạo ra các bản copy như struct, bởi vậy khi thay đổi thuộc tính của car2 thì car1 cũng bị thay đổi theo.

Note: Có thể kiểm tra 2 đối tượng có cùng trỏ tới 1 instance hay không bằng toán từ ===

Class có thể kế thừa, còn struct thì không

Class hỗ trợ kế thừa, có thể tạo ra các class con kế thừa từ class cha để mang những thuộc tính, phương thức của class cha. Có thể thấy class hỗ trợ lập trình OOP tốt hơn struct.

So sánh class và struct swift

Các phương thức trong struct nếu muốn thay đổi thuọc tính thì phải thêm mutating

Struct là kiểu value type. Mặc định thì các thuộc tính của 1 biến kiểu value type không thể bị sửa đổi trong các hàm của biến đó. Tuy nhiên, nếu bạn muốn thay đổi thuộc tính của 1 Struct bằng 1 phương thức bên trong nó, bạn phải khai báo mutating vào trước phương thức để làm:

So sánh class và struct swift
Nếu 1 hàm thay đổi thuộc tính mà không báo mutating thì trình biên dịch sẽ báo lỗi

Class hỗ trợ hàm deinit:

Class cung cấp hàm deinit. Hàm này được gọi trước khi 1 class được giải phóng khỏi memory.

Ví dụ về sự khác biệt struct và class thường dùng

Ví dụ như trong ví dụ sau đây đối với hàm repeating rất hay được sử dụng:

class Dog {
    var name = ""
}
let dogs = [Dog](repeating: Dog(), count: 3)
dogs[0].name = "Green"
dogs[1].name = "Red"
dogs[2].name = "Blue"
print("\(dogs[0].name) \(dogs[1].name) \(dogs[2].name)") // Blue Blue Blue

Bởi Dog là 1 class, nên 3 đối tượng Dog trong mảng dogs sẽ cùng trỏ tới 1 đối tượng giống nhau -> Vì vậy nên thay đổi giá trị của dogs[3] cũng sẽ thay đổi giá trị của các dog còn lại trong array.

Thử sửa Dog thành kiểu struct và print ra kết quả.

Khi nào nên sử dụng struct / class

Recommend sử dụng struct bởi:

  • Struct nhanh hơn class bởi struct sử dụng method dispatch là static dispatch, class sử dụng dynamic dispatch. Ngoài ra, struct lưu dữ liệu trong stack, còn class sử dụng stack + heap -> Xử lí trong class sẽ lâu hơn.
  • Class là 1 reference type. Do đó, nếu không cẩn thận khi truyền biến sẽ dễ gây ra lỗi ngoài ý muốn ( Xem phần value type vs reference type ở trên). -> Sử dụng struct sẽ an toàn hơn.

Nên sử dụng class khi:

  • Cần sử dụng kế thừa.
  • Cần sử dụng reference type

Kết luận:

Việc phân biệt được sự khác nhau giữa class và struct vô cùng quan trọng để có thể sử dụng cho đúng cách. Hi vọng qua bài viết, các bạn sẽ hiểu rõ hơn được về sự khác biệt giữa class và struct.