Kotlin学习笔记二

473 阅读3分钟

变量延迟初始化 lateinit var

使用 lateinit 来标识延迟初始化,使用::adapter.isInitialized判断是否已经初始化。

class MainActivity : AppcompatActivity(), View.OnClickListener {
	private lateinit val adapter:MessageAdapter
    override fun onCreate(saveInstanceState: Bundle?) {
    	// 判断是否已经初始化
    	if (!::adapter.isInitialized) {
    		adapter = MessageAdapter()
        }
    }
}

定义常量 companion object { const val TAG = "MainActivity" }

class MainActivity : AppcompatActivity() {
	companion object {
    	const val TAG = "MainActivity"
    }
}

扩展函数

扩展函数最好放在顶层函数,可以让扩展函数拥有全局访问域。

// 扩展函数语法接口
fun ClassName.methodName(param:T):T {}

fun String.lettersCount():Int {
	var count = 0
    for (char in this) { if (char.isLetter()) count++ }
    return count
}

fun String.lettersCount() = this.fold(0) { total, char -> total + if(char.isLetter()) 1 else 0 }

运算符重载

运算符重载写法,在类中使用operator加上指定操作符方法名。

// 运算符重载写法
class Xxx {
	operator fun plus(xxx:Xxx):Xxx {}
}

// 重载加法运算符方法
class Money(val value:Int) {
	operator fun plus(money: Money) = Money(value + money.value)
    operator fun plus(money: Int) = Money(value + money)
}
println(Money(3) + Money(5)) // 8
println(Money(4) + 5) // 9

操作符和方法名对照

表达式实际调用方法
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.minus(b)
a % ba.div(b)
a++a.inc()
a--a.dec
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()
a == ba.equals(b)
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a >= ba.compareTo(b) >= 0
a <= ba.compareTo(b) <= 0
a..ba.rangeTo(b)
a[b]a.get(b)
a[b] = ca.set(b, c)
a in bb.contains(a)
以上操作都可以重载重新定义。

扩展函数重载操作符

// kotlinUitls.kt
operator fun String.times(n:Int) = repeat(n)

"abc" * 3 // abcabcabc

高阶函数

定义:如果一个函数接收另外一个函数作为参数,或者返回值的类型是另外一个函数,那么该函数就是高阶函数。

函数类型:由参数和返回值组成,相同的参数和返回值可以看做同一种类型

// 函数类型,第一个参数String,第二个参数Int,返回值Int 的函数类型
(String,Int) -> Int

fun example(func:(String, Int) -> Unit) {
	func("hello", 123)
}
// HigherOrderFunction.kt
fun num1AndNum2(num1:Int,num2:Int, operator:(Int,Int) -> Int):Int {
	return operator(num1, num2)
}

fun plus(a:Int,b:Int) = a + b
fun minus(a:Int,b:Int) = a - b

fun main() {
    // ::plus 表示获取改函数的引用
    println(num1AndNum2(3, 5, ::plus)) // 8
    println(num1AndNum2(3, 5, ::minus)) // -2
    
    // 也可以使用Lambda表达式
    println(num1AndNum2(3, 5) { a,b -> a * b }) // 15
}

// 扩展StringBuilder类
fun StringBuilder.build(block: StringBuilder.() -> Unit()):StringBuilder { 
	block() 
    return this
}

StringBuilder().build {
	append("aa|")
	append("bb|")
}.toString()  // aa|bb|

内联函数

使用高阶函数会带来一些运行时的效率损失:每一个函数都是一个对象,并且会捕获一个闭包。 即那些在函数体内会访问到的变量。 内存分配(对于函数对象和类)和虚拟调用会引入运行时间开销。

但是在许多情况下通过内联化 lambda 表达式可以消除这类的开销。 下述函数是这种情况的很好的例子。即 lock() 函数可以很容易地在调用处内联。 考虑下面的情况:

高阶函数的函数在相当于java接口的匿名内部实现类,所以高阶函数的函数一般会创建匿名内部类,造成性能开销。

在高阶函数fun前添加inline表示内联函数。内联函数的参数函数内return相当于在整个内联函数的return。

fun testInlineFun1(str:String,call:(String)->Unit) {
	pritnln("call before")
	call(str)
	pritnln("call after")
}
fun main() {
	testInlineFun1("") { str-> if(str.isEmpty()) return@testInlineFun1 }
}
//call before
//call after

inline fun testInlineFun2(str:String,call:(String)->Unit) {
	pritnln("call before")
	call(str)
	pritnln("call after")
}
fun main() {
	testInlineFun2("") { str-> if(str.isEmpty()) return }
}
//call before

在inline修饰的内联函数,可以使用noinline来消除某个函数参数内联属性。

inline fun testInlineFun(noinline call1:()->Unit,call2:(String)->Unit) {}

在inline修饰的内联函数体内嵌套匿名内部类调用函数参数,要是crossinline修饰函数参数并且该函数不能有retrun操作。

inline fun testInlineFun(crossinline call:()->Unit) {
	val runnable = Runnable { call() }
    runnable.run()
}

高阶函数应用

// 在 SharedPreference.Editor 定义临时函数 block,block代码块里面上下文是SharedPreference.Editor
inline fun SharedPreferences.open(call: SharedPreferences.Editor.() -> Unit) {
    val editor = edit()
    editor.call()
    editor.apply()
}

SharedPreence("data", Context.MODE_PRIVATE).open{
	put("name", "tim");
    put("age", 18)
}
fun cvOf(vararg pairs:Pair<String, Any?>) = ContextValue().apply {
	for(pair in pairs) {
    	val key = pair.first
        val value = pair.second
        when(value) {
        	is Int -> put(key, value)
            is Long -> put(key, value)
            ...
            null -> putNull(key)
        }
    }
}

val contextValue = cvOf("a" to "aaa", "b" To 18)