➕ Operator Overloading
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Kotlin cho phép overload các operators (toán tử) cho các kiểu dữ liệu tự định nghĩa. Điều này cho phép sử dụng cú pháp tự nhiên như a + b, a[i], a in collection với các class của bạn.
2. Arithmetic Operators
Phần tiêu đề “2. Arithmetic Operators”Plus, Minus, Times, Div, Rem
Phần tiêu đề “Plus, Minus, Times, Div, Rem”| Expression | Function name |
|---|---|
a + b |
a.plus(b) |
a - b |
a.minus(b) |
a * b |
a.times(b) |
a / b |
a.div(b) |
a % b |
a.rem(b) |
data class Point(val x: Int, val y: Int) { operator fun plus(other: Point) = Point(x + other.x, y + other.y) operator fun minus(other: Point) = Point(x - other.x, y - other.y) operator fun times(scale: Int) = Point(x * scale, y * scale)}
fun main() { val p1 = Point(10, 20) val p2 = Point(5, 10)
println(p1 + p2) // Point(x=15, y=30) println(p1 - p2) // Point(x=5, y=10) println(p1 * 3) // Point(x=30, y=60)}Unary Operators
Phần tiêu đề “Unary Operators”| Expression | Function name |
|---|---|
+a |
a.unaryPlus() |
-a |
a.unaryMinus() |
!a |
a.not() |
++a, a++ |
a.inc() |
--a, a-- |
a.dec() |
data class Counter(val value: Int) { operator fun unaryMinus() = Counter(-value) operator fun inc() = Counter(value + 1) operator fun dec() = Counter(value - 1)}
fun main() { var counter = Counter(5)
println(-counter) // Counter(value=-5) println(++counter) // Counter(value=6) println(--counter) // Counter(value=5)}3. Compound Assignment Operators
Phần tiêu đề “3. Compound Assignment Operators”| Expression | Function name |
|---|---|
a += b |
a.plusAssign(b) |
a -= b |
a.minusAssign(b) |
a *= b |
a.timesAssign(b) |
a /= b |
a.divAssign(b) |
class MutablePoint(var x: Int, var y: Int) { operator fun plusAssign(other: MutablePoint) { x += other.x y += other.y }}
fun main() { val point = MutablePoint(10, 20) point += MutablePoint(5, 5) println("(${point.x}, ${point.y})") // (15, 25)}Lưu ý: Nếu định nghĩa cả
plusvàplusAssign, Kotlin sẽ ưu tiênplusAssigncho+=vớivar.
4. Comparison Operators
Phần tiêu đề “4. Comparison Operators”equals (==, !=)
Phần tiêu đề “equals (==, !=)”data class Person(val name: String, val age: Int) { override fun equals(other: Any?): Boolean { if (other !is Person) return false return name == other.name && age == other.age }
override fun hashCode() = name.hashCode() * 31 + age}
fun main() { val p1 = Person("Alice", 30) val p2 = Person("Alice", 30) val p3 = Person("Bob", 25)
println(p1 == p2) // true println(p1 == p3) // false println(p1 != p3) // true}Note:
data classtự động generateequals()vàhashCode().
compareTo (<, >, <=, >=)
Phần tiêu đề “compareTo (<, >, <=, >=)”| Expression | Function call |
|---|---|
a > b |
a.compareTo(b) > 0 |
a < b |
a.compareTo(b) < 0 |
a >= b |
a.compareTo(b) >= 0 |
a <= b |
a.compareTo(b) <= 0 |
data class Version(val major: Int, val minor: Int, val patch: Int) : Comparable<Version> { override fun compareTo(other: Version): Int { return when { major != other.major -> major - other.major minor != other.minor -> minor - other.minor else -> patch - other.patch } }}
fun main() { val v1 = Version(1, 0, 0) val v2 = Version(2, 0, 0) val v3 = Version(1, 5, 0)
println(v1 < v2) // true println(v3 > v1) // true println(v1 <= v1) // true}5. Indexed Access Operators
Phần tiêu đề “5. Indexed Access Operators”get và set
Phần tiêu đề “get và set”| Expression | Function call |
|---|---|
a[i] |
a.get(i) |
a[i, j] |
a.get(i, j) |
a[i] = b |
a.set(i, b) |
a[i, j] = b |
a.set(i, j, b) |
class Matrix(private val rows: Int, private val cols: Int) { private val data = Array(rows) { IntArray(cols) }
operator fun get(row: Int, col: Int): Int { return data[row][col] }
operator fun set(row: Int, col: Int, value: Int) { data[row][col] = value }}
fun main() { val matrix = Matrix(3, 3) matrix[0, 0] = 1 matrix[1, 1] = 5 matrix[2, 2] = 9
println(matrix[0, 0]) // 1 println(matrix[1, 1]) // 5}Ví dụ với Map-like class
Phần tiêu đề “Ví dụ với Map-like class”class MutableProperties { private val map = mutableMapOf<String, Any?>()
operator fun get(key: String): Any? = map[key] operator fun set(key: String, value: Any?) { map[key] = value }}
fun main() { val props = MutableProperties() props["name"] = "Alice" props["age"] = 30
println(props["name"]) // Alice println(props["age"]) // 30}6. in Operator (contains)
Phần tiêu đề “6. in Operator (contains)”| Expression | Function call |
|---|---|
a in b |
b.contains(a) |
a !in b |
!b.contains(a) |
data class Rectangle(val x: Int, val y: Int, val width: Int, val height: Int) { operator fun contains(point: Point): Boolean { return point.x in x until (x + width) && point.y in y until (y + height) }}
data class Point(val x: Int, val y: Int)
fun main() { val rect = Rectangle(0, 0, 100, 100) val p1 = Point(50, 50) val p2 = Point(150, 50)
println(p1 in rect) // true println(p2 in rect) // false println(p2 !in rect) // true}7. Range Operators
Phần tiêu đề “7. Range Operators”rangeTo (..)
Phần tiêu đề “rangeTo (..)”| Expression | Function call |
|---|---|
a..b |
a.rangeTo(b) |
a..<b |
a.rangeUntil(b) |
data class Date(val year: Int, val month: Int, val day: Int) : Comparable<Date> { override fun compareTo(other: Date): Int { return compareValuesBy(this, other, Date::year, Date::month, Date::day) }
operator fun rangeTo(other: Date) = DateRange(this, other)}
class DateRange( override val start: Date, override val endInclusive: Date) : ClosedRange<Date>, Iterable<Date> {
override fun iterator(): Iterator<Date> = DateIterator(start, endInclusive)}
class DateIterator(start: Date, private val end: Date) : Iterator<Date> { private var current = start
override fun hasNext() = current <= end
override fun next(): Date { val result = current current = current.nextDay() return result }}
fun Date.nextDay(): Date { // Simplified next day logic return Date(year, month, day + 1)}
fun main() { val start = Date(2024, 1, 1) val end = Date(2024, 1, 3)
for (date in start..end) { println(date) }}8. Invoke Operator
Phần tiêu đề “8. Invoke Operator”Cho phép gọi object như function:
class Greeter(private val greeting: String) { operator fun invoke(name: String) { println("$greeting, $name!") }}
fun main() { val greeter = Greeter("Hello") greeter("Alice") // Hello, Alice! greeter("Bob") // Hello, Bob!}Ví dụ: Builder pattern
Phần tiêu đề “Ví dụ: Builder pattern”class HtmlBuilder { private val content = StringBuilder()
operator fun invoke(block: HtmlBuilder.() -> Unit): String { block() return content.toString() }
fun div(text: String) { content.append("<div>$text</div>") }
fun p(text: String) { content.append("<p>$text</p>") }}
fun main() { val html = HtmlBuilder()
val result = html { div("Hello") p("World") }
println(result) // <div>Hello</div><p>World</p>}9. Iterator và Destructuring
Phần tiêu đề “9. Iterator và Destructuring”Iterator operator
Phần tiêu đề “Iterator operator”class Countdown(private val start: Int) { operator fun iterator(): Iterator<Int> { return object : Iterator<Int> { private var current = start override fun hasNext() = current >= 0 override fun next() = current-- } }}
fun main() { for (i in Countdown(5)) { print("$i ") // 5 4 3 2 1 0 }}Destructuring (componentN)
Phần tiêu đề “Destructuring (componentN)”class Person(val name: String, val age: Int, val city: String) { operator fun component1() = name operator fun component2() = age operator fun component3() = city}
fun main() { val person = Person("Alice", 30, "NYC")
val (name, age, city) = person println("$name, $age, $city") // Alice, 30, NYC
// Bỏ qua một số components val (n, _, c) = person println("$n from $c") // Alice from NYC}Note:
data classtự động generatecomponentN()functions.
10. Extension Operator Functions
Phần tiêu đề “10. Extension Operator Functions”Có thể định nghĩa operators như extension functions:
// Extension operator cho Stringoperator fun String.times(n: Int): String { return this.repeat(n)}
// Extension operator cho Listoperator fun <T> List<T>.times(n: Int): List<T> { return (1..n).flatMap { this }}
fun main() { println("Ha" * 3) // HaHaHa println(listOf(1, 2) * 3) // [1, 2, 1, 2, 1, 2]}📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| Category | Operators | Functions |
|---|---|---|
| Arithmetic | +, -, *, /, % |
plus, minus, times, div, rem |
| Unary | +a, -a, !a, ++, -- |
unaryPlus, unaryMinus, not, inc, dec |
| Comparison | ==, != |
equals |
| Comparison | <, >, <=, >= |
compareTo |
| Index | a[i], a[i] = b |
get, set |
| Contains | in, !in |
contains |
| Range | .., ..< |
rangeTo, rangeUntil |
| Invoke | a() |
invoke |
Best practices:
- Chỉ overload operators khi có ý nghĩa logic rõ ràng
- Operators nên có behavior nhất quán với kỳ vọng của người dùng
- Sử dụng
data classđể tự động cóequals,hashCode,componentN