kotlin 学习
kotlin 中使用 vararg 标记可变参数,调用方法:
// 定义
fun test(vararg books : String){...}
// 使用
test("疯狂iOS讲义", "疯狂Android讲义")
var arr = arrayOf("疯狂Kotlin讲义", "疯狂Java讲义")
// 将数组的多个元素传给个数可变的参数
test(*arr)
特性:直接使用函数类型
kotlin 中可直接使用函数类型作为参数和返回值,如
fun map(data : Array<Int>, fn: (Int) -> Int) : Array<Int>{...}
其中 fn: (Int) -> Int 就是使用函数类型,代表需要传入一个参数为 Int并且返回值为 Int 的函数。使用示例
// 设定一个方法
fun testfun(predicate: String):Boolean{
return predicate.length > 3;
}
// fn传入参数为String,返回值为 Boolean 的方法
fun useFun(a:String, fn:(String)->Boolean):String{
val b:Boolean = fn(a)
if (b) {return "big"} else {return "small"}
}
// 使用
var result:String = useFun("ja", ::testfun);
同理如使用函数作为返回值:
fun getMathFunc(type: String): (Int) -> Int {...}
关于 it 关键字
it:单个参数的隐式名称
一个 lambda 表达式只有一个参数是很常见的。
如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 ->。 该参数会隐式声明为 it:
ints.filter { it > 0 } // 这个字面值是“(it: Int) -> Boolean”类型的
调用示例:
// 省略形参名,用it代表形参
var square:(Int) -> Int = {it * it}
// 使用square调用Lambda
println(square(5)) // 输出25
println(square(6)) // 输出36
关于 lambda 表达式缩写
-
传统写法,直接传入匿名函数
var list = listOf("Java", "Kotlin", "Go") // 调用 List 的 dropWhile 方法需要传入 String->Boolean 类型的函数 // 传统写法,直接传入匿名函数 list.dropWhile(fun (predicate: String):Boolean{ return predicate.length > 3; })
-
第二种写法,提取匿名函数为一个方法
fun testfun(predicate: String):Boolean{ // 假设条件为大于3个字符的字符串 return predicate.length > 3; } // 需要传入一个函数参数,与传统写法无区别 var rt= list.dropWhile(::testfun)
-
第三种缩写,将方法定义为一个lambda表达式传参
var myfun = {predicate: String ->predicate.length > 3} var rt = list.dropWhile(myfun)
-
第四种缩写,将Lambda表达式放在括号后面,无需使用命名参数,省略形参名,用it代表形参
var rt = list.dropWhile() {it.length > 3}
-
第五种缩写,省略了 () ,最后一个参数是Lambda表达式,可将表达式写在括号外面
var rt = list.dropWhile{it.length > 3}
lambda 调用
定义Lambda表达式,并在它后面增加圆括号可调用该Lambda表达式
var result = {base: Int , exponent:Int ->
var result = 1
for (i in 1 .. exponent) {
result *= base
}
result
}(4, 3)
forEach 中的 lambda
var list = listOf(3, 5, 30, -25, 14)
// 使用匿名函数执行forEach()方法
list.forEach(fun(n) {
println("元素依次为:${n}")
// 匿名函数中的return用于返回该函数本身,会打印出全部原始
return
})
// 使用Lambda表达式执行forEach()方法
list.forEach{n->
println("元素依次为:${n}")
// Lambda表达式中的return用于返回它所在的函数(main函数),只打印第一个元素
return
}
// 使用Lambda表达式执行forEach()方法
list.forEach(){n ->
println("元素依次为:${n}")
// 使用限定返回,此时return只是返回传给forEach方法的Lambda表达式,什么都不打印
return@forEach
}
在类中自定义 getter 和setter 方法
kotlin 的getter 和setter 方法不走寻常路,需要注意
class Person(name: String, age: Int){
// 使用private修饰属性,将这些属性隐藏起来
var name = name
set(newName){
// 执行合理性校验,要求用户名必须在2~6位之间
if (newName.length > 6 || newName.length < 2){
println("您设置的人名不符合要求")
} else {
field = newName
}
}
get() {
println("执行 name 的getter方法")
return "Alexander ken"
}
// 定义private修饰的属性,该属性是幕后使用
private var _age: Int = age
var age
// 重写getter方法,返回幕后属性的值
get() = _age
set(newAge){
// 执行合理性校验,要求用户名必须在2~6位之间
if (newAge > 100 || newAge < 0){
println("您设置的年龄不合法")
} else {
// 对幕后属性赋值
_age = newAge
}
}
var fullName
// 使用单表达式定义getter方法的方法体
get() = "${name}"
set(value) {
println("执行fullName的setter方法")
// 如果value字符串中不包含.或包含几个.都不行
if ("." !in value || value.indexOf(".") != value.lastIndexOf(".")) {
println("您输入的fullName不合法")
} else {
var tokens = value.split(".")
}
}
}
fun main(args: Array<String>) {
var p = Person("李刚", 29)
p.age = 120 // 赋值非法,不能赋值失败
println(p.age) // 删除29
p.age = 25 // 赋值合法,赋值成功
println(p.age) // 输出25
println(p.name)
println(p.fullName)
}
实现接口
kotlin 与 java 的接口实现方式不同,在java 中我们可以直接 new 一个接口对象出来,但是 kotlin 需要使用 object 关键字,如实现 ActivityLifecycleCallbacks 接口:
val activityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
......
override fun onActivityDestroyed(activity: Activity) {
}
}
另外需要注意将 :
TODO("not implemented")
这句 TODO 删除,否则会抛出异常:kotlin.NotImplementedError: An operation is not implemented: not implemented
“TODO("not implemented")” 这句代码,这句代码在运行的时候会抛出以上异常,这样做的好处是促使我们去实现接口方法或者手动删掉这句代码。
关于 kotlin 中的 ? 与 !! 以及 ?: 三个运算符的解释
这篇博客解释得不错,就不解释了
Kotlin中?和!!的区别
https://www.jianshu.com/p/51b2e5aa3dd8