Kotlin函数

Kotlin函数用法全面分析

前言:)
现代编程语言最有趣的 10 大特性
1 Pipeline operator
2 Pattern matching
3 Reactive (Rx) programming build in the language
4 Lambda
5 Destructuring
6 Cascade operator
7 If expressions
8 Try expressions
9 Automatic currying
10 Method extensions
11 Optional chaining
12 DSL

正文:)

1.声明
Java

    public  String function(String param){
        return param.concat("!");
    }

Kotlin

    fun function(param: String): String {
        return "$param!"
    }

Kotlin

  • 修饰符 默认public
  • 返回值 后置位声明(推导可省)
  • 参数 类型后置
  • 函数体 fun关键字声明 单表达式可省{},return
fun function(param: String) = "$param!"

2.顶层函数
函数是一等公民
不在类中,直接声明在kt文件最外层

3.局部函数
与Java不同:作用域不同,变量名可重

fun outter() {
    var a:String
    fun inner() {
        var a:String
    }
}

4.匿名函数

    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
        if (value == 3) return  // 局部返回到匿名函数的调用者,即 forEach 循环
        print(value)
    })

赋值给变量

val anonymous = fun(s: String): Int { return s.toIntOrNull() ?: 0 }

5.缺省参数
Java里面有重载
Kotlin采用了默认参数值

fun read(a: Array = emptyArray(), b: Int = 0, c: Int = a.size) { /*……*/
}

//1不关心顺序 2有缺省值
val read = read(c = 1, b = 2)

6.var在fun中不被允许 ,构造函数除外

class classA(var str: String) {}

7.解构声明

    val map1 = mapOf("1" to 1, "2" to 2)
    map1.forEach { key, value -> println("$key&$value!") }
    //缺省值
    map1.forEach { _, value -> println("$value!") }

    //数组解构
    val (param, value) = "param=car=c".split("=")
    val (c, car) = "param=car=c".split("=").reversed()

8.高阶函数(函数作为参数传递)

  • 声明参数为"函数类型"
  • 函数类型表示法 (x: Int, y: Int) -> Point
fun funA1(fun1: (i: Int) -> String) : String {
   return fun1(1)
}

9.声明函数类型别名

typealias Alias = (Int) -> String
fun test(a: Alias) {}

10.Lambdas 表达式

  • 相当于匿名函数, 刻画了映射关系, 无需为其起名字
  • Lambdas 表达式是花括号括起来的代码块
  • 参数声明可省, ->箭头可省
  • 当 lambda 函数的输入只有一个参数时,可以省略掉参数定义,用 it 代替
  • Lambdas函数的返回值为 最后一个表达式的值 或者显式return返回
val lambda = { x: Int, y: Int -> {x+y} }
val lambda = { x: Int, y: Int -> x+y }

11.Lambdas作为函数实参传递

fun test(func: (Int) -> String) {
    func(1) 
}
fun main() {
    val lambda = { x: Int -> x.toString() }
    test(lambda)
    test({ x: Int -> x.toString() })
}

Lambda 表达式 是 最后一个实参 ,可以拿到括号外面

    test() { x: Int -> x.toString() }
    //近一步省略 ()
    test /*()*/ { x: Int -> x.toString() }
    //近一步省略 x:Int ->  省略成 it (单个参数的隐式名称)
    test { it.toString() }

拖尾 Lambda 表达式

fun foo(i: Int = 0, lambda: () -> Unit) { /*……*/
} 
val foo1 = foo(lambda = { println("hello") })
val foo2 = foo(1) { println("hello") }
val foo3 = foo { println("hello") }

Lambda 表达式的返回值为 最后一个表达式的值 或者显式返回

    test {
        val a = it + 1
        return@test a.toString()
    }
    test tag@{
        val a = it + 1
        return@tag a.toString()
    }

Lambda 与高阶

fun safeRun(runnable: () -> Unit) {
    try {
        runnable()
    } catch (t: Throwable) {
        t.printStackTrace()
    }
}

fun testNormalSafeRun() {
    safeRun {
        System.out.println("testNormalSafeRun")
    }
}

12.函数类型实例化

//仅是声明
fun isOdd2(x: Int) = x % 2 != 0
//已是实例
val lambdaIsOdd = { x: Int -> x % 2 != 0 }
//已是实例
val isOdd1 = fun(x: Int) = x % 2 != 0

fun testLdb() {
    val numbers = listOf(1, 2, 3)
    //实例化,传递引用
    numbers.filter(::isOdd2) 
    //实例化的直接传递
    numbers.filter(lambdaIsOdd)
    numbers.filter(isOdd1)
    numbers.filter { x: Int -> x % 2 != 0 }
}

13.LINQ-风格

函数式编程
比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程
倡导利用若干简单的执行单元让计算结果不断渐进
逐层推导复杂的运算,而不是设计一个复杂的执行过程。

data class DataA(val name: String, val age: Int)

fun testLINQ() {
    var list = ArrayList()
    repeat(10) {
        list.add(DataA("gaom$it", 10 + it))
    } 
    //容器的内置扩展函数
    list
        .filter { it.age >= 15 }
        .sortedByDescending { it.age }
        .map { it.age }
        .joinToString(separator = "-", prefix = "(", postfix = ")")
        .run { print(this) }
    //>>> (19-18-17-16-15)

    //容器的 asSequence
    println(list
        .asSequence()
        .map { it.name }
        .filter { it.startsWith("gaom") }
        .toList())
    //>>> [gaom0, gaom1, gaom2, gaom3, gaom4, gaom5, gaom6, gaom7, gaom8, gaom9]
    // 找到第一个平方大于3的数,输出它的平方
    println(listOf(1, 2, 3, 4, 5)
        .asSequence()
        .map { it * it }
        .find { it > 3 })
    //>>> 4
}

14.闭包

非纯函数 访问修改了其作用域外的变量
Lambda 表达式或者匿名函数(以及局部函数和对象表达式)
可以访问其 闭包 ,即在外部作用域中声明的变量。

fun testClosure() {
    var sum = 0
    val ints = listOf(1, 2, 3, 4, 5)
    ints
        .filter { it > 0 }
        .forEach {
            //请注意 这里传递给forEach方法的是整个{}也就是Lambda也就是匿名方法 ,
            //1 首先java不支持方法做为参数传递
            //2 其次java匿名内部类访问局部变量需要将局部变量final
            sum += it
        }
    print(sum)//>>>15
}

15.可变参数

fun funVararg(vararg strings: String) { /*……*/
} 
val funVararg1 = funVararg("a", "b", "c")
val funVararg2 = funVararg(strings = *arrayOf("a", "b", "c"))

16.表达式

val singleExpression1 = 1 * 2
val singleExpression2 = { println("hello") }

17.when()

fun testWhen(any: Any) = when (any) {
    is String -> any.length
    is List<*> -> any.size
    else -> 0
}

18.扩展函数

定义在类外的任何地方,定义类.方法名
扩展函数不能访问私有的或者受保护的成员
使得你可以像调用成员方法一般,调用扩展函数
扩展函数,让 JVM 上的静态语言,也能拥有像动态语言一般,扩展语言特性的能力。
爱用扩展函数 而不是创建工具类Utils

fun String.concat(str:String)="$this$str"
println("1".concat("2"))//12
fun  T?.println() = println(this)
"1".println()
  1.println()

19.作用域函数
下面只做with函数的源码分析,其他同理可证
with

    //with源码
    //接收俩个参数,1是泛型T 2是泛型T的一个扩展函数(无入参,返回值为泛型R)
    //with调用第一个参数T的block方法,block也就是with的第二个参数,并把block的返回值作为自己的函数返回值
    public inline fun  with(receiver: T, block: T.() -> R): R {
        return receiver.block()
   }
   //示例
   val b1: Boolean = with("123") {//lambda(省略了参数声明和箭头,并且lambda作为with的第二个实参可以拿到括号外声明)
        //lambda作为泛型T的扩展函数,所以其作用域在T(String类)内部,也就是this即为"123"
        println(this)
        this.toBoolean()//可以省略this.调用,其返回值是lambda的返回值,也是with的返回值
    }
    

run

    //源码
    public inline fun  run(block: () -> R): R {
        return block()
    }
    //示例
    val b2: Boolean = run {
        println("")
        "123"
    }.toBoolean()
    
    //实用性场景分析 : 简化部分相同操作,如下两个变量都调用了show方法
    run {
        if (firstTimeView) introView else normalView
    }.show()

T.run

    val b3: Boolean = "123".run {
        println(this)
        toBoolean()//省略this.
    }

T.let

    val b4: Boolean = "123".let { a ->
        //a替换it 也可省略
        println(a)
        a.toBoolean()
    }
    
    //操作符配合使用
    nullVal?.let {
        println("[nullVal] not null code block")
    } ?: run {
        println("[nullVal] null code block")
    }

20.Kotlin DSL
//示例1

fun kotlinDSL(block: StringBuilder.() -> Unit) {
    block(StringBuilder("Kotlin"))
}

fun testDSL1() {
    // 调用高阶函数
    kotlinDSL {
        // 这个 lambda 的接收者类型为StringBuilder
        append(" DSL")
        println(this)
    }
}

//示例2

class Model {
    var id: String = ""
    var name: String = ""
    var subItem: SubItem? = null

    class SubItem {
        var id: String = ""
        var name: String = ""
    }
}

inline fun Model(config: Model.() -> Unit) : Model {
    val result = Model()
    config(result)
    return result
}
//调用
Model { 
    id = "123"
    name = "Name" 
}

21.自定义操作符

operator fun String.rem(other: String?): String {
    return this + (other ?: "")
} 
operator inline fun Int.rem(blk: () -> Unit) {
    if (Random(System.currentTimeMillis()).nextInt(100) < this) blk()
} 
fun testOperator2() {
    val result = run { "" % "" }
    50 % { "你有一半的几率看到我!".println() } 
}

22.中缀调用
简化了 "a.(b)" 转化成中缀 "a 中缀 b"

    val pair :Pair   = "1" to 1
    val map1 = mapOf("1" to 1, "2" to 2)

自定义中缀

object 烟雨
object 天青色 {
    infix fun 等(word: 烟雨) {
        println("天青色等烟雨")
    }
} 
infix fun Int.除(i: Int): String = "" 
fun main3(args: Array) {
    天青色 等 烟雨
    9 除 3 === "除了你还是你~"
    Love You 3000
}
object Love {
    infix fun You(i: Int) {
        println("I Love U 3000")
    }
}

23.invoke
Kotlin 提供了 invoke 约定,可以让对象向函数一样直接调用

class Person(val name: String) {
    operator fun invoke() {
        println("my name is $name")
    }
}

fun testInvoke1() {
    val person = Person("geniusmart")
    person()
}

24.实现Gradle依赖声明

class Dependencies {
    fun compile(coordinate: String) {
        println("add $coordinate")
    }

    operator fun invoke(block: Dependencies.() -> Unit) {
        block()
    }
}

fun testInvoke2() {
    val dependencies = Dependencies()
    dependencies {
        compile("com.android.support:appcompat-v7:27.0.1")
        compile("com.android.support.constraint:constraint-layout:1.0.2")
    }
// 等价于:
    dependencies.compile("com.android.support:appcompat-v7:27.0.1")
    dependencies.compile("com.android.support.constraint:constraint-layout:1.0.2")
}

BONUS TIME

http://fuckjava.com

你可能感兴趣的:(Kotlin函数)