Swift - Mutating Func trong Struct

Càng ngày, Struct càng được sử dụng nhiều hơn, và mình thật sự bối rối khi không hiểu từ "mutating" được thêm vào khi viết hàm cho struct dùng để làm gì? Sau khi tìm hiểu rõ về value typereference type, thì bắt đầu hiểu ra ít nhiều. Để mô tả thêm rõ hơn, mình xin lấy Rectangle (Hình chữ nhật) struct để mô tả cho thêm chi tiết:

struct Rectangle {
    var width = 1
    var height = 1
}

The Mutating Keyword - Khi nào sử dụng từ khóa Mutating

Đầu tiên, hãy thêm hàm tính diện tích cho nó:

struct Rectangle {
    var width = 1
    var height = 1
     
    func area() -> Int {
        return width * height
    }
}

Hàm này sẽ sử dụng chiều ngang và dọc có sẳn để tính và trả về kết quả. Điểm quan trọng ở đây là hàm này không thay đổi bất cứ biến giá trị nào của Struct, chỉ sử dụng giá trị có sẳn của Struct đó. Vậy ngược lại, chúng ta thêm một hàm Scale Rectangle (phóng to, thu nhỏ) cho struct:

struct Rectangle {
    var width = 1
    var height = 1
 
    mutating func scaleBy(value: Int) {
        width *= value
        height *= value
    }
}

Hãy chú ý rằng, hàm này có khả năng thay đổi giá trị biến (height và width) của Struct Rectange. Vậy ta thấy, khi nào hàm có khả năng thay đổi biến giá trị trong struct thì mình sẽ thêm từ khóa "mutating" vào hàm đó.

Using A Mutating Function - Dùng để làm gì?

Lần đầu tiên viết hàm mutating, mình khá ngạc nhiên (hoặc bối rối) khi việc này xãy ra:

Bạn có thể thấy hiển thị Error như thế thì chẳng giải quyết được gì nếu bạn không hiểu về cách làm việc của mutating. Để fix được Error này: Whoa!! hết error. vậy tại sao thế?

Why Var?

Error ở trên chỉ xuất hiện khi thêm "mutating" trong hàm. Nên nhớ, Struct là value type (biến giá trị), đồng nghĩa nó là immutable (không thể thay đổi nội dung). Vậy khi gọi một hàm "mutating" thì swift sẽ tạo thêm bộ nhớ mới dự theo thêm bộ nhớ cũ và tính toán trong hàm đó rồi lại được gán cho biến MyRect nên bắt buộc biến MyRect phải là biến Var để có thể nhận lại một giá trị mới. Trường hợp không thêm "mutating" và để biến myRect là "let" thì sao. Tất nhiên là không thiể build được rồi, vì Struct không cho phép thay đổi chính nó mà không phải từ một hàm mutating.

Conclude:

Qua đây ta hiểu được phần nào cách hoạt động của Struct và nguyên nhân tại sao mình phải thêm từ khóa "mutating" vào trong hàm trong struct. Link tham khảo: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html