Kotlin 函数
函数声明
1.覆盖方法总是使用与基类型方法相同的默认参数值。 当覆盖一个带有默认参数值的方法时,必须从签名中省略默认参数值
2.如果一个函数不返回任何有用的值,它的返回类型是
Unit
// 使用 fun
fun xxx(x: Int): Int {
return x * x
}
open class A {
//函数参数可以添加默认值
open fun show(a: Int = 0 , b: Int = 1) {
println( a + b)
}
}
class AA: A() {
override fun show(a: Int, b: Int) {
}
//单表达式函数
fun show1() : Int = 2
//编译器推断返回值类型
fun show2() = 2
}
fun main() {
val a = A()
a.show(b = 2) // 可以省略部分默认有默认值的参数
}
可变数量的参数(Varargs)
1.函数的参数(通常是最后一个)可以用
vararg修饰符标记2.在函数内部,类型
T的vararg参数的可见方式是作为T数组,即上例中的ts变量具有类型Array <out T>
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
//调用
val list = asList(1, 2, 3)
中缀表示法
1.标有 infix 关键字的函数也可以使用中缀表示法(忽略该调用的点与圆括号)调用。中缀函数必须满足以下要求:
2.中缀函数总是要求指定接收者与参数。当使用中缀表示法在当前接收者上调用方法时,需要显式使用
this
infix fun Int.shl(x: Int): Int { …… }
// 用中缀表示法调用该函数
1 shl 2
// 等同于这样
1.shl(2)
// this 使用
class MyStringCollection {
infix fun add(s: String) { …… }
fun build() {
this add "abc" // 正确
add("abc") // 正确
add "abc" // 错误:必须指定接收者
}
}
函数作用域
1.Kotlin 中函数可以在文件顶层声明
2.Kotlin 中函数也可以声明在局部作用域、作为成员函数以及扩展函数
// 函数内定义函数 嵌套函数
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
泛型函数
函数可以有泛型参数,通过在函数名前使用尖括号指定
fun <T> singletonList(item: T): List<T> { …… }
内联函数
1.内联函数是C++的增强特性之一,用来降低程序的运行时间。当内联函数收到编译器的指示时,即可发生内联:编译器将使用函数的定义体来替代函数调用语句,这种替代行为发生在编译阶段而非程序运行阶段
2.
inline修饰符影响函数本身和传给它的 lambda 表达式3.内联可能导致生成的代码增加;不过如果我们使用得当(即避免内联过大函数),性能上会有所提升,尤其是在循环中的“超多态(megamorphic)”调用处
高阶函数
1.高阶函数是将函数用作参数或返回值的函数
2.使用高阶函数会带来一些运行时的效率损失:每一个函数都是一个对象,并且会捕获一个闭包。 即那些在函数体内会访问到的变量。 内存分配(对于函数对象和类)和虚拟调用会引入运行时间开销
3.
it是在当一个高阶函数中Lambda表达式的参数只有一个的时候可以使用it来使用此参数。it可表示为单个参数的隐式名称,是Kotlin语言约定的
fun show1(a: (String) -> String): String {
return a("0")
}
fun main() {
println(show1 { it + "22" })
}
Lambda 表达式
1.lambda表达式就是一个匿名函数
2.在lambda中不可用直接使用return ,可以使用return+label这种形式
3.在使用
Lambda表达式的时候,可以用下划线(_)表示未使用的参数,表示不处理这个参数。
// 按钮点击事件
mBtn.setOnClickListener(object : View.OnClickListener{
override fun onClick(v: View?) {
Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show()
}
})
//等同于
mBtn.setOnClickListener { Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show() }
val map = mapOf("key1" to "value1","key2" to "value2","key3" to "value3")
map.forEach{
key , value -> println("$key \t $value")
}
// 不需要key的时候
map.forEach{
_ , value -> println("$value")
}
尾递归函数
1.Kotlin 支持一种称为[尾递归]的函数式编程风格。 这允许一些通常用循环写的算法改用递归函数来写,而无堆栈溢出的风险
2.当一个函数用
tailrec修饰符标记并满足所需的形式时,编译器会优化该递归,留下一个快速而高效的基于循环的版本3.要符合
tailrec修饰符的条件的话,函数必须将其自身调用作为它执行的最后一个操作。在递归调用后有更多代码时,不能使用尾递归,并且不能用在 try/catch/finally 块中。目前尾部递归只在 JVM 后端中支持
// 使用
val eps = 1E-10 // "good enough", could be 10^-15
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))
// 等于
val eps = 1E-10 // "good enough", could be 10^-15
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y = Math.cos(x)
if (Math.abs(x - y) < eps) return x
x = Math.cos(x)
}
}