Destructuring declaration là một tính năng Kotlin cho phép bạn phân rã một đối tượng thành nhiều biến trong một biểu thức duy nhất. Cú pháp val (name, age) = user khai báo đồng thời hai biến, gán cho chúng các giá trị từ các thành phần của đối tượng. Theo tài liệu Kotlin (2026), việc hủy cấu trúc giảm khối lượng mã khi làm việc với data class xuống 30–50%. Destructuring declaration làm cho mã ngắn gọn và dễ đọc hơn.
Các điểm chính
val (a, b) = obj để phân rã đối tượng thành các biếnDestructuring declaration (khai báo hủy cấu trúc) là một cấu trúc cú pháp Kotlin cho phép bạn phân rã một thể hiện lớp thành nhiều biến trong một biểu thức duy nhất. Phía bên trái chứa danh sách các biến trong dấu ngoặc đơn, phía bên phải chứa đối tượng được phân rã. Kotlin tự động gọi hàm componentN() tương ứng cho mỗi biến, trong đó N là số thứ tự của biến trong dấu ngoặc đơn.
Khai báo hủy cấu trúc thường được sử dụng nhất với data classes. Trình biên dịch Kotlin tự động tạo component1(), component2(), v.v. cho mỗi data class — dựa trên số lượng thuộc tính trong hàm tạo chính. Đối với các lớp thông thường không có bộ sửa đổi data, componentN() không được tạo, nhưng có thể được định nghĩa thủ công dưới dạng hàm toán tử với từ khóa operator.
Khai báo hủy cấu trúc đã trở thành một mẫu phổ biến nhờ khả năng đơn giản hóa mã khi làm việc với các bộ sưu tập cặp, kết quả hàm và lặp Map. Thay vì viết person.firstName, person.lastName, nhà phát triển viết val (firstName, lastName) = person. Điều này giảm số dòng và cải thiện khả năng đọc, đặc biệt là trong các vòng lặp và lambda.
Khi gặp cấu trúc val (a, b) = obj, trình biên dịch Kotlin tạo ra mã sau: val a = obj.component1(); val b = obj.component2(). Nếu các biến được khai báo với var, các phép gán var được tạo ra. Kiểu của mỗi biến được suy ra từ kiểu trả về của hàm componentN() tương ứng. Điều này có nghĩa là khai báo hủy cấu trúc hoàn toàn an toàn về kiểu và được kiểm tra tại thời điểm biên dịch.
data class Person(val firstName: String, val lastName: String, val age: Int)
fun main() {
val person = Person("Alice", "Smith", 30)
// Hủy cấu trúc: component1(), component2(), component3()
val (firstName, lastName, age) = person
println("$firstName $lastName, $age tuổi")
}
Trong danh sách, Person là một data class với ba thuộc tính. Kotlin tạo component1() → firstName, component2() → lastName, component3() → age. Biểu thức val (firstName, lastName, age) = person gọi các hàm này và gán kết quả. Quan trọng: tên biến không cần phải khớp với tên thuộc tính — trình biên dịch chỉ xem xét thứ tự của componentN() và kiểu của chúng. Bạn chỉ có thể phân rã N thuộc tính đầu tiên, bỏ qua phần còn lại.
Data classes là ứng cử viên chính cho khai báo hủy cấu trúc. Mỗi data class tự động nhận được componentN() cho tất cả các thuộc tính của hàm tạo chính. Thứ tự của componentN() tương ứng với thứ tự khai báo thuộc tính. Điều này có nghĩa là khi bạn thay đổi thứ tự các trường trong một data class, thứ tự các biến trong hủy cấu trúc cũng thay đổi — điều này có thể dẫn đến các lỗi tiềm ẩn.
// Hủy cấu trúc Pair
val pair = Pair("key", 42)
val (key, value) = pair
println("$key -> $value")
// Hủy cấu trúc Triple
val triple = Triple("A", "B", "C")
val (first, second, third) = triple
// Map.Entry trong vòng lặp
val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
println("$k = $v")
}
Pair và Triple là các lớp tiêu chuẩn có hủy cấu trúc tích hợp cho hai và ba thành phần. Pair thường được sử dụng làm kiểu trả về cho các hàm cần trả về hai giá trị liên quan mà không cần tạo một data class riêng. Trong vòng lặp for trên Map.Entry, cấu trúc (k, v) = entry phân rã khóa và giá trị thông qua component1() và component2(). Đây là mẫu tiêu chuẩn để lặp qua Map trong Kotlin, thay thế hoàn toàn các lời gọi tường minh tới key và value.
Nếu một số thành phần không cần thiết trong quá trình hủy cấu trúc, Kotlin cho phép bạn thay thế chúng bằng gạch dưới _. Điều này cải thiện khả năng đọc — người đọc ngay lập tức thấy rằng thành phần đó đang bị bỏ qua. Ngoài ra, việc sử dụng _ ngăn chặn việc truy cập vô tình vào một biến chưa được khởi tạo: trình biên dịch không tạo bất kỳ biến nào cho _, loại bỏ các cảnh báo về biến không sử dụng.
data class Order(
val id: Long,
val customerName: String,
val amount: Double,
val status: String
)
fun process(orders: List<Order>) {
for ((id, _, amount) in orders) {
println("Đơn hàng $id: $amount")
}
}
Trong danh sách, Order có bốn thuộc tính, nhưng vòng lặp chỉ cần id và amount. Gạch dưới ở vị trí customerName báo cho trình biên dịch “bỏ qua component2()”. Kotlin không gọi component2() và không tạo biến cho thành phần này. Quan trọng: gạch dưới chỉ có thể được sử dụng trong khai báo hủy cấu trúc, không phải trong hàm tạo data class. Nếu nhiều thành phần liên tiếp bị bỏ qua, mỗi thành phần sẽ có gạch dưới riêng.
Đối với các lớp không có bộ sửa đổi data, bạn có thể tự định nghĩa componentN() bằng cách thêm từ khóa operator. Điều này cho phép bạn sử dụng khai báo hủy cấu trúc với bất kỳ lớp nào, bao gồm cả các lớp bên thứ ba mà mã nguồn không thể sửa đổi — chỉ cần viết một hàm mở rộng với operator. Cách tiếp cận này đặc biệt hữu ích cho các lớp thư viện và các lớp Java không có componentN() tự động.
class Rect(val width: Int, val height: Int)
operator fun Rect.component1(): Int = width
operator fun Rect.component2(): Int = height
// Cho lớp Java có getters
operator fun Dimension.component1(): Int = width
operator fun Dimension.component2(): Int = height
fun main() {
val rect = Rect(1920, 1080)
val (w, h) = rect
println("Độ phân giải: ${w}x${h}")
}
Trong ví dụ, Rect là một lớp thông thường không có data. Các hàm mở rộng với operator fun component1() = width và component2() = height thêm hỗ trợ hủy cấu trúc. Tương tự cho java.awt.Dimension: một phần mở rộng operator trên Dimension cho phép phân rã nó thành width và height. Giới hạn: số lượng thành phần tối đa cho khai báo hủy cấu trúc là 5. Về mặt lý thuyết, bạn có thể định nghĩa component6() và cao hơn, nhưng Kotlin sẽ không tạo cú pháp tương ứng cho 6+ biến trong dấu ngoặc đơn.
Câu hỏi thường gặp
Có, mọi data class tự động nhận được componentN() cho tất cả các thuộc tính của hàm tạo chính. Các thuộc tính được khai báo trong thân lớp (sử dụng tham số hàm tạo không có val/var) không tạo componentN().
Nếu val (a, b, c) = obj có một đối tượng chỉ có hai hàm component, trình biên dịch sẽ báo lỗi. Nếu có ít biến hơn (val (a) = pair), Kotlin sẽ chỉ gọi component1() và bỏ qua component2() — sẽ không có lỗi nào xảy ra.
Có, Map.Entry hỗ trợ hủy cấu trúc: val (key, value) = map.entries.first(). Hủy cấu trúc không hoạt động trên toàn bộ Map cùng một lúc — chỉ từng phần tử, trong vòng lặp for hoặc thông qua bộ lặp.
Có, Kotlin hỗ trợ hủy cấu trúc trong tham số lambda: map.forEach { (k, v) -> ... }. Đối với data classes trong tham số lambda, bạn cần thêm dấu ngoặc đơn lồng nhau xung quanh tham số.
Kotlin hỗ trợ tối đa 5 biến trong một khai báo hủy cấu trúc. Nếu bạn cần phân rã nhiều hơn năm thuộc tính, hãy kết hợp chúng thành các data class lồng nhau hoặc sử dụng Pair/Triple bên trong một biến duy nhất.
Tổng kết
val (a, b) = obj, phân rã một đối tượng thành nhiều biến trong một biểu thức duy nhấtChúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm