Trong ngôn ngữ lập trình Swift, struct được sử dụng rất phổ biến nhờ vào tính hiệu quả và sự nhẹ nhàng của nó so với class. Một trong những khía cạnh quan trọng khi làm việc với struct trong Swift là cách xử lý dữ liệu thông qua các phương thức nonmutating.
Struct trong Swift khác với class ở chỗ chúng là kiểu giá trị, tức là mỗi lần một struct được ghi vào biến mới hoặc truyền vào hàm, nó sẽ sao chép toàn bộ giá trị của nó. Điều này giúp tăng tính an toàn cho dữ liệu, vì bất kỳ thay đổi nào được thực hiện trên một copy của struct sẽ không ảnh hưởng đến các copy khác.
Trong struct, mặc định tất cả các phương thức đều là nonmutating, nghĩa là chúng không thể thay đổi bất kỳ biến nào trong struct đó. Điều này được đảm bảo bằng cách sử dụng từ khóa self
không đổi. Để minh họa rõ hơn, dưới đây là ví dụ cụ thể:
struct MyStruct {
var value: Int
func incrementValue() {
// self.value += 1 // Lỗi xảy ra vì 'self' là không đổi trong phương thức nonmutating
}
}
Nếu bạn muốn thay đổi biến value
trong phương thức incrementValue
, thì bạn cần phải đánh dấu phương thức đó với từ khóa mutating
:
struct MyStruct {
var value: Int
mutating func incrementValue() {
value += 1
}
}
Tuy nhiên, nếu mục tiêu của bạn là ngăn chặn sự thay đổi của biến trong quá trình thực thi phương thức nonmutating, có một số cách tiếp cận bạn có thể sử dụng.
Sử dụng từ khóa let
Điều đầu tiên bạn cần nhớ là việc khai báo struct với từ khóa let
ngăn tất cả các phương thức, ngay cả khi đánh dấu là mutating
, thay đổi thuộc tính của struct đó.
let myStructInstance = MyStruct(value: 5)
myStructInstance.incrementValue() // Lỗi biên dịch: cannot use mutating member on immutable value
Sử dụng sao chép (Copy)
Sinh ra tính không thay đổi thông qua việc sao chép thực sự là cách tự nhiên khi làm việc với struct. Khi bạn gọi một phương thức nonmutating, dữ liệu sẽ không thay đổi do cơ chế sao chép.
/* Thay đổi struct thông qua gán copy */
Thiết kế phương thức nonmutating đúng cách
Một cách nữa để đảm bảo rằng dữ liệu của bạn không bị thay đổi là thiết kế phương thức nonmutating cẩn thận. Đảm bảo rằng tất cả các thay đổi chỉ được thực hiện trên bản sao của các biến, không phải trên các biến thực sự.
struct MyStruct {
var value: Int
func incrementedCopy() -> MyStruct {
var copy = self
copy.value += 1
return copy
}
}
var instance = MyStruct(value: 5)
let newInstance = instance.incrementedCopy()
print(instance.value) // Output: 5
print(newInstance.value) // Output: 6
Trong đoạn mã trên, phương thức incrementedCopy
tạo ra một bản sao của struct hiện tại, rồi thực hiện thay đổi trên bản sao đó và trả về. Kết quả là bản gốc không bị thay đổi.
Bao bọc thuộc tính trong phương thức
Một cách khác là bao bọc thuộc tính trong phương thức bằng cách sử dụng cấu trúc dữ liệu bất biến hoặc các môi trường kiểm soát truy cập.
Kết luận, việc ngăn chặn thay đổi biến trong các phương thức nonmutating của struct trong Swift là một quyết định thiết kế quan trọng giúp giữ cho dữ liệu của bạn an toàn và nguyên bản. Bằng cách sử dụng một trong những cách tiếp cận nêu trên, bạn có thể đảm bảo rằng dữ liệu của bạn không bị thay đổi ngoài ý muốn trong suốt quá trình vận hành của ứng dụng.
Comments