接着上一篇Kotlin开发安卓APP笔记-函数和lambda表达式(2)继续学习
使用“vararg”关键字修饰参数,即可定义为可变数量参数(一般是最后一个参数):
fun asList(vararg ts: Any): List {
val result = ArrayList()
for (t in ts) {
result.add(t)
}
return result
}
等同Java版:
List<Object> asList(Object... ts){
List<Object> result=new ArrayList<>();
for (Object t:ts) {
result.add(t);
}
return result;
}
该函数可以接收不定个数参数:
val list = asList(1, 2, 3)
val list2 = asList("bestmk.cn","猫客技术论坛")
在函数内部,被“vararg”修饰的参数实际上是一个数组(Array< out T>)。
一个函数,只能有一个参数可以使用“vararg”关键字修饰,一般放在最后一个参数。若不是最后一个参数,在使用时,其他的参数可以使用命名参数(Named Arguments)方式;或者函数有一个功能类型参数,可以在函数的后面定义一个Lambda表达式实现。
// vararg参数不是最后一个参数情况
fun asMultipleList(vararg ts: Int, multiple: Int): List {
val resultL = ArrayList()
for(data in ts) {
resultL.add(data * multiple)
}
return resultL
}
//
var multiList = asMultipleList(1, 2, 3, multiple=2)
println(multiList)
//后面更有功能类型参数
fun showInfo(vararg infos: String, show: (info: String) -> Unit) {
for(info in infos) {
show(info)
}
}
//
showInfo("info1", "info2") {
println(it)
}
调用一个“vararg”函数时,可以一个一个值使用,如“asList(1, 2, 3)”;也可以直接使用一个存在的数组数据,使用“*”关键字:
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
很多教程都是将Infix放在扩展函数前面,不合理,即使会Java也不方便理解,所以先学习扩展函数
所谓扩展函数就是扩展类的函数, 即 Extension Function , 可以在已有类中添加新的方法, 比继承更加简洁和优雅。在Kotlin中,允许对类进行扩展,不需要继承或使用 Decorator 模式,通过一种特殊形式的声明,来实现具体实现某一具体功能。扩展函数是静态解析的,并未对原类增添函数或者属性,也就是说对其本身没有丝毫影响。
扩展函数定义方式:
fun receiverType.functionName(params){
body
}
receiverType:表示函数的接收者,也就是函数扩展的对象
functionName:扩展函数的名称
params:扩展函数的参数,可以为NULL
扩展函数并没有对原类做修改,而是为被扩展类的对象添加新的函数。
fun Int.add(vararg nums:Int):Int{
var result:Int=0
for (num in nums)result=result+num
return result
}
为Int声明了一个扩展函数add,用来计算多个数相加的结果,学习一定要灵活,将学到的东西灵活运用起来
使用方式:add(1,2,3)
或者 1.add(1)
在实际开发时,如果对一个类某一功能并不通用,只有某些特殊场景使用时,可以使用扩展函数,从而显得灵活多变。
之前说过,扩展函数是静态解析的,也就是,它并不是接收者类型的虚拟成员,意味着调用扩展函数时,调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的的对象表达式来决定的,而不是动态的类型决定的。比如先声明了两个类Person和Teacher,其中teacher继承于Person,
在测试实例中,分别对Person和Teacher声明了扩展函数doFly(),又声明了fly()方法,其参数是一个Person对象,在其方法体内,调用了Person的扩展函数。现在测试实例中,创建了一个Teacher对象teacher,调用fly()方法并将teacher过去,实际上会调用哪个扩展函数呢?
open class Person {
}
class Teacher: Person() {
}
// 测试实例
fun Person.doFly() {
println("Person do fly")
}
fun Teacher.doFly() {
println("Teacher do fly")
}
fun fly(person: Person) {
person.doFly()
}
fun main(args: Array) {
var teacher: Teacher = Teacher()
fly(teacher)
}
// Log
Person do fly
从Log打印中,可以清晰的看到的是,fly(teacher)调用的是Person的扩展函数。因为调用哪个函数, 仅仅是由参数person声明的类型决定, 这里参数person的类型为Person类.
现在我们了解了扩展函数,再来看中缀表达式infix
使用Infix需要满足以下三个条件:
1,它们是成员函数或扩展函数
2,他们有一个单一的参数
3,他们用infix关键字标记
例如刚刚写的add函数例子用中缀表达式就可以写为:1 add 2,增加了代码的美观性
kotlin可以不需要像Java一样创建一个类来保存函数,直接在顶层写函数,除顶层函数之外,Kotlin函数也可以声明为本地函数,作为成员函数和扩展函数。
Kotlin支持本地函数,即另一个函数内的函数:
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
本地函数可以访问外部函数的局部变量(即闭包),所以在上面的例子中,visited可以是局部变量:
fun dfs(graph: Graph) {
val visited = HashSet()
fun dfs(current: Vertex) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v)
}
dfs(graph.vertices[0])
}
成员函数是在类或对象内定义的函数:
class Sample() {
fun foo() { print("Foo") }
}
成员函数用点符号调用:Sample().foo()
函数可以具有在函数名称前使用尖括号指定的泛型参数:
fun <T> singletonList(item: T): List<T> {
// ...
}
今天先学习到这里,我去吃饭先,明天学习内联函数,高阶函数和lambda表达式,尾递归函数