Kotlin函数

作者: gaom明 | 来源:发表于2019-11-20 14:55 被阅读0次

    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<Byte> = 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<DataA>()
        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> 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 <T, R> 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 <R> 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<String,Int>   = "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<String>) {
        天青色 等 烟雨
        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函数

        本文链接:https://www.haomeiwen.com/subject/yiyoictx.html