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ó
associatedtypekhông thể được sử dụng trực tiếp làm kiểu dữ liệu (Containerkhô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!


