Kotlin语法 | 青训营

69 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第5天

今天来记录一下 kotlin 的基本语法

变量、常量

  • 基本使用:keyword name : type = value

    • 常量:

      val a: Int = 1  // immediate assignment
      val b = 2   	// `Int` type is inferred
      val c: Int  	// Type required when no initializer is provided
      c = 3       	// deferred assignment
      
    • 变量:

      var x = 5 // `Int` type is inferred
      x += 1
      

变量类型

  • 概念:Kotlin只提供引用类型这一种数据类型,但是,Kotlin编译器会在Java字节码中改用基本数据类型,以提高其性能

  • 基本数据类型:

    类型位宽度
    Double64
    Float32
    Long64
    Int32
    Short16
    Byte8
  • Nothing类型:

    • TODO函数的任务就是抛出异常,永远不会运行成功,返回Nothing类型

表达式

  • 条件表达式if

    • 常规应用:

      fun max(a: Int,b: Int): Int{
          if (a > b) return a
          else return b
      }
      
    • 作为条件表达式:kotlin没有三目运算符,用if表达式代替

      fun max(a: Int,b: Int) = if (a > b) else b
      
  • 条件表达式when

    when (x){
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> {
            print("x is neither 1 nor 2")
        }
    }
    

函数

  • 定义:fun name(parameters): ReturnType{}

  • 案例:

    • 常规定义:

      fun sum(a: Int, b: Int): Int {
          return a + b
      }
      
    • 函数体为表达式:此时返回值类型会自动推断

      fun sum(a: Int, b: Int) = a + b
      
    • 带缺省值的函数:

      fun printInfo(name: String = "name",age: Int = 18){
          print(name)
          print(age)
      }
      
    • Kotlin的函数参数可以用形参名指定,可以不按顺序

      fun printInfo(name: String = "name",age: Int = 18){
          print(name)
          print(age)
      }
      
      // 调用
      fun main(args: Array<String>){
          printInfo(age = 9,name = "happy")
      }
      
  • 可变长参数函数:vararg进行标识

    fun vars(vararg v: Int){
        for(vt in v){
            print(vt)
        }
    }
    
    // 测试
    fun main(args: Array<String>) {
        vars(1,2,3,4,5)  // 输出12345
    }
    
  • TODO函数:

    // 原型
    public inline fun TODO(reason: String): Nothing = throw NotImplementedError;
    
    // 测试
    fun main(args: Array<String>){
        var i = 1
        if (i > 3){
            println(i)
        }else {
            TODO("no reason");
        }
        i++
        println(i)
    }
    
  • 匿名函数:如果有返回值,默认会返回最后一个语句的值

    • 匿名函数没有参数时:

      fun main(args: Array<String>) {
          val total: Int = "Mississippi".count()
          println(total)
          // 匿名函数,lambda
          val totals: Int = "Mississippi".count { letter -> letter == 's' }
          println(totals)
      }
      
    • 匿名函数带参数时,则参数的类型放在匿名函数的类型定义中,参数名放在函数定义中:

      fun main(args: Array<String>) {
          val countS: (String) -> Int = { str->
              str.count { letter->letter == 's' }
          }
          println(countS("Mississippi"))
      }
      
    • it关键字:定义只有一个参数的匿名函数时,可以用it关键字表示参数名。

      fun main(args: Array<String>) {
          val countS: (String) -> Int = {
              it.count { letter->letter == 's' }
          }
          println(countS("Mississippi"))
      }
      
  • lambda:

    • 优缺点:

      • 好处:更灵活、编写更高效
      • 坏处:在JVM上,lambda会以对象实例的形式存在,JVM会为所有同lambda打交道的变量分配内存,导致内存开销变大,可能带来严重的性能问题
    • 解决方案:函数内联:inline

      • 解决原理:函数内联可以讲lambda直接复制到需要用到的地方,避免了内存开销
      • 注:使用lambda的递归函数不能使用内联,否则会导致无限复制粘贴,内存爆炸都是有可能的,因此当这么使用时,编译器会发出警告
    • 范例:

      fun main(args: Array<String>) {
          val getDiscountWords = {goodsName:String,hour:Int ->
              val currentYear = 2017
              "$currentYear year $goodsName $hour"
          }
          showOnBoard("happy", getDiscountWords)
      }
      
      fun showOnBoard(goodsName:String,getDiscountWords: (String,Int)->String){
          val hour:Int = (1..24).shuffled().last()
          println(getDiscountWords(goodsName,hour))
      }
      
  • 函数引用:

    • 引入:要把函数作为参数传给其他函数使用,除了传lambda表达式, kotlin还提供了其他方法,即传递函数引用,函数引用可以把一个具名函数转换成一个值参,使用lambda表达式的地方,都可以使用函数引用。

      fun main(args: Array<String>) {
          showOnBoard("happy", ::getDiscountWords)
      }
      
      fun showOnBoard(goodsName:String,getDiscountWords: (String,Int)->String){
          val hour:Int = (1..24).shuffled().last()
          println(getDiscountWords(goodsName,hour))
      }
      
      fun getDiscountWords(goodsName: String,hour: Int): String{
          val currentYear = 2017
          return "$currentYear year $goodsName $hour"
      }
      

循环

  • for循环:

    val items = listOf("apple", "banana", "kiwifruit")
    for (item in items) {
        println(item)
    }
    
  • while循环:

    val items = listOf("apple", "banana", "kiwifruit")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index++
    }
    
  • 循环控制跳转:

    • 跳出当前循环体:break
    • 结束本次循环,进入下一次循环:continue

集合类

  • 常见集合类:列表(List)集(Set)映射(Map)

  • 分类:可变集合类、不可变集合类

    • 可变集合:Mutable,可写入、删除、修改、读取数据
    • 不可变集合:Immutable,只能读取数据
  • 可变集合类:

    • 创建方法:listOf()setOf()mapOf()

    • 使用:

      val list = listOf(1, 2, 3, 4, 5, 6, 7)
      val set = setOf(1,2,3,4)
      val map = mapOf(1 to "a", 2 to "b", 3 to "c")
      
  • 不可变集合:

    • 创建方法:MutableListOf(),MutableSetOf(),MutableMapOf()

    • 使用:

      val mutableList = mutableListOf("a", "b", "c")  //创建可变MutableList
      val mutableSet = mutableSetOf("a", "b", "c") //创建可变的MutableSet
      val mutableMap = mutableMapOf(1 to "X", 2 to "Y", 3 to "Z")
      
  • 遍历集合的元素:List、Set类 继承了 Iterable 接口,扩展了 forEach() 函数来遍历元素;Map类也扩展了 forEach() 函数来遍历元素

    • foreachit表示当前元素

      list.forEach {
           println(it)
      }
      
      set.forEach {
           println(it)
      }
      
      map.forEach {
           println("K = ${it.key}, V = ${it.value}")
      }
      
    • for循环for 可以循环遍历任何提供了Iterator的对象

      for (item in collection) print(item)