函数声明使用fun关键字
fun double(x: Int): Int {
}
函数调用
val result = double(2) //调用普通函数
Sample().foo() // create instance of class Sample and calls foo//调用类成员函数
使用infix标记
// Define extension to Int
infix fun Int.shl(x: Int): Int {
...
}
1 shl 2 等同于 1.shl(2)
函数的参数定义
fun powerOf(number: Int, exponent: Int) {
...
}
给参数默认值
fun read(b: Array, off: Int = 0, len: Int = b.size()) {
...
}
给参数命名(调用时使用的名称)
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
...
}
reformat(str) 等同于 reformat(str, true, true, false, '_')
//也可以下面这样调用
reformat(str, wordSeparator = '_')//增加代码的可读性
返回Unit的函数,如果一个函数返回的是无用的,那么可以用Unit作为返回值
fun printHello(name: String?): Unit {
if (name != null)
println("Hello ${name}")
else
println("Hi there!")
// `return Unit` or `return` is optional
}
Unit可以被推断,所以也可以忽略
fun printHello(name: String?) {
...
}
函数也可以写成一行
fun double(x: Int): Int = x * 2
//因为Int可以被推断,所以也可以省略
fun double(x: Int) = x * 2
函数的可变参数,可以用vararg修饰
fun asList(vararg ts: T): List {
val result = ArrayList()
for (t in ts) // ts is an Array
result.add(t)
return result
}
//调用如下
val list = asList(1, 2, 3)
注意:可变参数和Java一样,只可以修饰一个参数,而且必须是最后的。
在kotlin中,函数可以定义在top-level,不需要创建一个class来使用函数
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())
}
class Sample() {
fun foo() { print("Foo") }
}
//调用如下
Sample().foo() // creates instance of class Sample and calls foo
fun <T> singletonList(item: T): List<T> {
// ...
}
之前的有介绍过。
fun lock(lock: Lock, body: () -> T): T {
lock.lock()
try {
return body()
}
finally {
lock.unlock()
}
}
//调用如下
fun toBeSynchronized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchronized)
//使用lambda
val result = lock(lock, { sharedResource.operation() })
//把表达式移除来
lock (lock) { sharedResource.operation() }
看另外一个典型的例子
fun List.map(transform: (T) -> R): List {
val result = arrayListOf()
for (item in this)
result.add(transform(item))
return result
}
//调用如下
List ints = ...
val doubled = ints.map { value -> value * 2 }
//可以使用it来代替
val doubled = ints.map { it * 2 }
//使用LINQ方式
strings.filter { it.length == 5 }.sortBy { it }.map { it.toUpperCase() }
因为使用高阶函数,每个函数都有个闭包,内存的分配和虚拟的调用都会带来运行时开销。通过内联lambda表达式可以减少这方面的开销。
lock(l) { foo() }
lock函数可以在调用的地方很容易被内联,内联lock函数之后,可以避免为参数foo()创建一个函数对象而自动 生成一个调用,编译器会使用如下代码
l.lock()
try {
foo()
}
finally {
l.unlock()
}
上面这种方式是不是我们一开始就想要的这种!怎么内联lock函数呢
inline fun lock<T>(lock: Lock, body: () -> T): T {
// ...
}
inline默认会函数本身和lambda表达式,可以对参数使用noinline
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
// ...
}
注意下面的区别:
fun foo() {
ordinaryFunction {
return // ERROR: can not make `foo` return here
}
}
fun foo() {
inlineFunction {
return // OK: the lambda is inlined
}
}
注意下面
inline fun f(crossinline body: () -> Unit) {
val f = object: Runnable {
override fun run() = body() //只有使用crossinline才可以在内部里调用lambda表达式
}
// …
}
使用Reified的具体类型参数
假如我们有如下代码:
fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
var p = parent
while (p != null && !clazz.isInstance(p)) {
p = p.parent
}
@Suppress("UNCHECKED_CAST")
return p as T?
}
调用方式:
treeNode.findParentOfType(MyTreeNode::class.java)
是不是感觉很复杂。。。可能你想下面这样调用
treeNode.findParentOfType<MyTreeNode>()
所以你需要重新定义函数如下:
inline fun TreeNode.findParentOfType(): T? {
var p = parent
while (p != null && p !is T) {
p = p.parent
}
return p as T?
}
你也可以下面这样
inline fun membersOf() = T::class.members
fun main(s: Array) {
println(membersOf().joinToString("\n"))
}
属性也可以被内联
val foo: Foo
inline get() = Foo()
var bar: Bar
get() = ...
inline set(v) { ... }
//也可以对整个属性内联
inline var bar: Bar
get() = ...
set(v) { ... }
使用tailrec修饰,下面两段代码等同,可以自己理解下。
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))
private fun findFixPoint(): Double {
var x = 1.0
while (true) {
val y = Math.cos(x)
if (x == y) return y
x = y
}
}