0

Advanced Kotlin tips: tail recursion, sealed classes, local, infix and inline functions and more…

Local functions Các chức năng cục bộ rất hữu ích cho việc reuse code, chỉ cần cẩn thận không lạm dụng chúng để tránh nhầm lẫn.

fun foo(a: Int) {
    fun local(b: Int) {
        return a + b
    }
    return local(1)
}

Infix functions Chức năng Infix cho khả năng đọc tốt, vì nó cho phép gõ một cái gì đó ví dụ như là "test" foo "x" , cảm giác khá code khá thoáng dễ nhìn

infix fun String.foo(s: String) {
    ...
}
// Call extension function.
"test".foo("x")
// Or call extension function using infix notation.
"test" foo "x"

Chức năng infix phải có một tham số Inline functions Một biểu thức lambda trong Kotlin được dịch sang các class Java anonymous trong Java 6 hoặc 7, điều đó thực hiện ở tầng trên. Lambda gọi đến stask, nên nó có ảnh hưởng đến hiệu suất. Chức năng inline thì có thể được sử dụng để gọi thẳng đến thay vì phải gọi qua một phương thức khác. Vì thế nó tạo nên ý nghĩa của việc sử dụng chức năng inline thông qua thằng lambda

inline fun callBlock(block: () -> Unit) {
    println("Before calling block")
    block()
    println("After calling block")
}

Khi chúng tôi gọi callBlock nó sẽ được dịch đến một vài thứ như sau:

callBlock { println("The block operation") }
// Rough java bytecode
String var1 = "Before calling block";
System.out.println(var1)
String var2 = "The block operation";
System.out.println(var2);
var1 = "After calling block";
System.out.println(var1);

trường hợp chức năng không được đánh dấu như là inline

callBlock { println("The block operation") }
// Rough java bytecode
callBlock((Functinos0)null.INSTANCE);

Bạn phải cẩn thận với chức năng inline mặc dù vì nó sao chép nội dung phương pháp các văn bản nơi mà nó được gọi và nếu phần body của các chức năng là quá lớn, thì bạn thực sự không muốn làm điều này. Do đó, điều sau đây rõ ràng là không có ý nghĩa vì nó chẳng cho ra kết quả gì

inline fun foo(noinline block: () -> Unit) {// Single lambda marked as noinline
inline fun foo() { // No lambdas

tail recursion By using tailrec we let the compiler know that it can replace the method call with a for loop or goto statement. You can only use it if the last call in a function is only calling itself and only itself. Bằng việc sử dụng tailrec chúng ta cho phép trình biên dịch biết rằng nó có thể thay thế việc gọi method với một vòng lặp for hoặc một lệnh goto. Bạn chỉ có thể sử dụng nó nếu cuộc gọi cuối cùng trong một chức năng chỉ gọi chính nó và chỉ chính nó.

tailrec fun findFixPoint(x: Double = 1.0): Double         
        = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

Sealed classes According to Kotlin reference we should use sealed classes for representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type. Theo tài liệu tham khảo Kotlin, chúng ta nên sử dụng sealed classes để đại diện cho các class phân cấp bị hạn chế, khi một giá trị có thể có một kiểu từ một tập giới hạn, nhưng không thể có bất kỳ loại nào khác. Nói cách khách khi trả về các kiểu khác nhau có liên quan thì là tốt

sealed class Response 
data class Success(val content: String) : Response() 
data class Error(val code: Int, val message: String) : Response() 
fun getUrlPage(url: String) : Response {
    val valid = // Some logic here!
    if (valid) {
        return Success("Content")
    else {
        return Error(404, "Not found")
    }
}
// Here is the beauty of it.
val response = getUrlPage("/")
when (response) {
     is Success -> println(response.content)
     is Error -> println(response.message)
}

Sealed classes phải được định nghĩa trong một file độc lập

Một vài lời khuyên nhỏ cho các bạn như sau Local return Khá là hữu ích với lambda, nhưng chúng ta hãy giải thích nó với một đoạn code cơ bản, bạn nghĩ return cái gì đầu tiên trong đoạn code sau?

fun foo(list: List<String>): Boolean {
    list.forEach {
        if (...) {// Some condition.
           return true
        }
    }
    return false
}

nếu được để foo return true, bạn cũng có thể chọn để chỉ trả về trong khoảng forEach Nếu điều đó không có nhiều ý nghĩa, kiểm tra đoạn code sau:

fun foo() {
    Observable.just(1)
                .map{ intValue ->
                    return@map intValue.toString() 
                }
                ...
}

nếu chúng ta đã dùng ***return***trong đoạn code trên, nó sẽ return đến foo cái mà không có nhiều ý nghĩa ở đây, return@map đây chính là cái kết quả của chức năng map, cái mà được trả về có chủ ý


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí