Trong Swift, associatedtype
được sử dụng trong protocol
để định nghĩa một kiểu dữ liệu liên kết (associated type), giúp protocol trở nên linh hoạt hơn mà không cần chỉ định trước một kiểu dữ liệu cụ thể.
1. Cách sử dụng cơ bản
Khi một protocol có associatedtype
, kiểu dữ liệu đó sẽ được quyết định bởi class, struct hoặc enum tuân theo protocol đó.
protocol Container {
associatedtype Item
func add(_ item: Item)
func getAll() -> [Item]
}
Ở đây, Container
là một protocol định nghĩa một kiểu Item
nhưng chưa chỉ định kiểu cụ thể.
2. Triển khai protocol có associatedtype
Khi một struct hoặc class tuân theo Container
, nó phải xác định Item
là kiểu dữ liệu cụ thể nào:
struct IntContainer: Container {
typealias Item = Int // Không bắt buộc phải khai báo typealias, Swift tự suy luận được.
private var items: [Int] = []
func add(_ item: Int) {
items.append(item)
}
func getAll() -> [Int] {
return items
}
}
Hoặc với kiểu generic:
struct GenericContainer<T>: Container {
typealias Item = T
private var items: [T] = []
func add(_ item: T) {
items.append(item)
}
func getAll() -> [T] {
return items
}
}
3. Sử dụng với where
để ràng buộc kiểu
Bạn có thể ràng buộc associatedtype
bằng where
để yêu cầu kiểu đó tuân theo một protocol khác:
protocol Identifiable {
var id: String { get }
}
protocol Repository {
associatedtype Model: Identifiable
func getById(_ id: String) -> Model?
}
struct User: Identifiable {
let id: String
let name: String
}
struct UserRepository: Repository {
typealias Model = User
private var users: [User] = [
User(id: "1", name: "Alice"),
User(id: "2", name: "Bob")
]
func getById(_ id: String) -> User? {
return users.first { $0.id == id }
}
}
4. Lưu ý khi sử dụng associatedtype
- Một protocol có
associatedtype
không thể được sử dụng trực tiếp làm kiểu dữ liệu (Container
không thể dùng làm kiểu của biến). - Để dùng một protocol với
associatedtype
, có thể sử dụng generic hoặc type erasure (AnyContainer
).
Ví dụ về type erasure:
struct AnyContainer<T>: Container {
typealias Item = T
private let _add: (T) -> Void
private let _getAll: () -> [T]
init<C: Container>(_ container: C) where C.Item == T {
_add = container.add
_getAll = container.getAll
}
func add(_ item: T) {
_add(item)
}
func getAll() -> [T] {
return _getAll()
}
}
Hy vọng giúp bạn hiểu rõ hơn về associatedtype
trong Swift!
