Kotlin基础语法

Kotlin说明

        Kotlin是一种在Java虚拟机上运行的静态类型编程语言,被称之为Android世界的Swift,Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言,足见Kotlin将来会成为android开发的主流语言。

        本文从Kotlin基础语法为入口,先了解一下Kotlin的基本数据类型,之后再阐述Kotlin中的运算符,最后在陈述一下Kotlin的条件控制及循环控制结构。本文只做Kotlin入门的参考资料,如有谬误、纰漏,望大家多多指教。

Kotlin基本数据类型

        Kotlin中的基本数据类型包含:数值、字符、布尔、数组、字符串。

数值

        Kotlin数值类型包含Byte、Short,Int、Long、Float、Double等。不同于Java,字符不属于数值类型,是一个独立的数据类型。

类型位宽度
Byte8
Short16
Int32
Long64
Float32
Double64

字面常量

  • 十进制:1024
  • 长整型:1024L
  • 16进制:0x0F
  • 2进制:0b00011001
  • 注意:8进制不支持
  • Floats 使用 f 或者 F 后缀:134.5f
  • Doubles:12.5,123.5e10

字符

        和 Java 不一样,Kotlin 中的 Char 不能直接和数字操作,Char 必需是单引号 ' 包含起来的。比如普通字符 '9','o'。如下写法是错误的:

fun check(c: Char) {
    if (c == 1) { // 错误:类型不兼容
        // ……
    }
}

         字符字面值用单引号括起来: '1'。 特殊字符可以用反斜杠转义。 支持这几个转义序列:\t、 \b、\n、\r、\'、\"、\\ 和 \$。 编码其他字符要用 Unicode 转义序列语法:'\uFF00'。我们可以显式把字符转换为 Int 数字:

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
        throw IllegalArgumentException("Out of range")
    return c.toInt() - '0'.toInt() // 显式转换为数字
}

布尔 

        布尔用 Boolean 类型表示,它有两个值:true 和 false。内置的布尔运算有:

|| – 短路逻辑或
&& – 短路逻辑与
! - 逻辑非

 数组

        数组用类 Array 实现,并且还有一个 size 属性及 get 和 set 方法,由于使用 [] 重载了 get 和 set 方法,所以我们可以通过下标很方便的获取或者设置数组对应位置的值。数组的创建两种方式:一种是使用函数arrayOf();另外一种是使用工厂函数。如下所示:

//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })

//读取数组内容
Log.d(TAG,a[0].toString())    // 输出结果:1
Log.d(TAG,b[1].toString())     // 输出结果:2

        如上所述,[] 运算符代表调用成员函数 get() 和 set()。注意: 与 Java 不同的是,Kotlin 中数组是不协变的(invariant)。除了类Array,还有ByteArray, ShortArray, IntArray,用来表示各个类型的数组,省去了装箱操作,因此效率更高,其用法同Array一样:

val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]

字符串 

        和Java一样,String是不可变的。方括号[]语法可以很方便的获取字符串中的某个字符,也可以通过for循环来遍历:

for (c in str) {
    Log.d(TAG,c.toString())
}

         Kotlin支持三个引号"""扩起来的字符串,支持多行字符串,比如:

val text = """
多行字符串
多行字符串
"""
Log.d(TAG,text)   // 输出有一些前置空格

字符串模板

        字符串可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($)开头,由一个简单的名字构成:

  • $ 表示一个变量名或者变量值
  • $varName 表示变量值
  • ${varName.fun()} 表示变量的方法返回值
var a = 1
// 模板中的简单名称:
val s1 = "a is $a" 

a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"

        或者用花括号扩起来的任意表达式: 

 val s = "hello world"
 val str = "$s.length is ${s.length}" // 求值结果为 "hello world.length is 11"

         原生字符串和转义字符串内部都支持模板。 如果你需要在原生字符串中表示字面值 $ 字符(它不支持反斜杠转义),你可以用下列语法:

val price = "${'$'}9.99"
Log.d(TAG,price)

Kotlin基础语法

函数定义

一般函数定义格式

        函数定义使用关键字fun,参数格式为:参数名: 类型,如:

fun sum(a: Int, b: Int): Int {   // Int 参数,返回值 Int
    return a + b
}

        表达式作为函数体,返回类型自动推断:

fun sum(a: Int, b: Int) = a + b

public fun sum(a: Int, b: Int): Int = a + b   // public 方法则必须明确写出返回类型

        无返回值的函数(类似Java中的void) :

fun printSum(a: Int, b: Int): Unit { 
    Log.d(TAG,(a + b).toString())
}


// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
public fun printSum(a: Int, b: Int) { 
    Log.d(TAG,(a + b).toString())
}

可变长参数函数

        函数的变长参数可以用vararg关键字进行标识:

fun vars(vararg v:Int){
    for(vt in v){
        Log.d(TAG,vt.toString())
    }
}

lambda(匿名函数)

        lambda表达式使用实例:

val sumLambda: (Int, Int) -> Int = {x,y -> x+y}

 定义常量与变量

变量定义

        变量定义使用var关键字,定义格式如下:

var <标识符> : <类型> = <初始化值>

 常量定义

        变量定义使用val关键字,只能赋值一次的变量(类似Java中final修饰的变量),定义格式如下:

val <标识符> : <类型> = <初始化值>

         常量与变量都可以没有初始化值,但是在引用前必须初始化,编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。

val a: Int = 1
val b = 1       // 系统自动推断变量类型为Int
val c: Int      // 如果不在声明时初始化则必须提供变量类型
c = 1           // 明确赋值


var x = 5        // 系统自动推断变量类型为Int
x += 1           // 变量可修改

注释 

        Kotlin 支持单行和多行注释,与 Java 不同的是,Kotlin 中的块注释允许嵌套。格式如下:

// 这是一个单行注释

/* 这是一个多行的
   块注释。 */

NULL检查机制 

        Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理。

//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1

        当一个引用可能为 null 值时, 对应的类型声明必须明确地标记为可为 null。 如:当 str 中的字符串内容不是一个整数时, 返回 null:

fun parseInt(str: String): Int? {
  // ...
}

 区间

        区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:

for (i in 1..4) Log.d(TAG,i.toString()) // 输出“1234”

for (i in 4..1) Log.d(TAG,i.toString()) // 什么都不输出

if (i in 1..10) { // 等同于 1 <= i && i <= 10
    Log.d(TAG,i.toString())
}

// 使用 step 指定步长
for (i in 1..4 step 2) Log.d(TAG,i.toString()) // 输出“13”

for (i in 4 downTo 1 step 2) Log.d(TAG,i.toString()) // 输出“42”


// 使用 until 函数排除结束元素
for (i in 1 until 10) {   // i in [1, 10) 排除了 10
     Log.d(TAG,i.toString())
}

运算符

        作为一门计算机语言,运算符是必不可少的,Kotlin提供了一套丰富的运算符来操作变量,我们可以把运算符分成以下几类:

  • 算术运算符
  • 关系运算符
  • 位运算符
  • 逻辑运算符
  • 赋值运算符
  • 其他运算符

算术运算符

        算术运算符用在数学表达式中,他们的作用和数学的作用一样。下表中列出了所有的算术运算符。

运算符 描述
+加法-运算符两侧的值相加
-减法-左操作数减右操作数
*乘法-运算符两侧的值相乘
/除法-左操作数除以右操作数,如果两个操作数为正数,为取商
%取余-做操作数除以做操作数的余数
++自增-操作数的值增加1,对应方法为inc()
--自减-操作数的值减1,对应方法为dec()

实例代码

 var  a = 3
 var b = 5
 Log.d(TAG,"a = " + a +" b = " + b)
 Log.d(TAG,"a + b = " + (a + b)) //加法
 Log.d(TAG,"a - b = " + (a - b)) //减法
 Log.d(TAG,"a * b = " + (a * b)) //减法
 Log.d(TAG,"a / b = " + (a / b)) //减法
 a++
 Log.d(TAG,"a++" + a) //自增
 b--
 Log.d(TAG,"b--" + b) //自减

运行结果

关系运算符

        Kotlin中的关系运算符如下表所示:

运算符描述
==检查两个操作数的值是否相等,如果相等则为真。相当于Java中的equals
===检查两个操作数的引用是否相等,如果相等则条件为真。相当于Java中的==。
!=检查两个操作数的值是否相等,如果不相等则条件为真。
!==检查两个操作数的引用是否相等,如果不相等则条件为真。相等于Java中的!=
>检查左操作数的值是否大于右操作数,如果是则条件为真。
<检查左操作数的值是否小于右操作数,如果是则条件为真。
>=检查左操作数的值是否大于或等于右操作数,如果是则为真。
<=检查左操作数的值是否小于或等于右操作数,如果是则为真。

实例代码

  var  a = String("5".toByteArray())
  var b = String("5".toByteArray()) //a、b为两个值相等的不同对象
  var c = "5"
  var d = "5"
  Log.d(TAG,"a == b = " + (a == b))  
  Log.d(TAG,"a === b = " + (a === b))
  Log.d(TAG,"c == d = " + (c == d))
  Log.d(TAG,"c === d = " + (c === d))

  Log.d(TAG,"a != b = " + (a != b))
  Log.d(TAG,"a !== b = " + (a !== b))
  Log.d(TAG,"c != d = " + (c != d))
  Log.d(TAG,"c !== d = " + (c !== d))
  Log.d(TAG,"a > b = " + (a > b))
  Log.d(TAG,"a < b = " + (a < b))
  Log.d(TAG,"a >= b = " + (a >= b))
  Log.d(TAG,"a <= b = " + (a <= b))

运行结果

位运算符

        对于Int和Long类型,还有一系列的位操作符可以使用,如下表所示:

符号或方法说明
and 、and(bits)按位与
or 、or(bits)按位或
inv()按位非
xor 、xor(bits)按位异或
shl、shl(bits)左移运算符
shr、shr(bits)右移运算符
ushr、ushr(bits)无符号右移运算符

注意:and、or、xor、shl、shr、ushr即可以直接使用关键字,也可以调用对象的的方法。

实例代码

 var a = 0b001001
 var b = 0b001001
 var c = 0b001000
 var d = -0b001000
 Log.d(TAG,"a and b = " +a.and(b))
 Log.d(TAG,"a and b = " +(a and b))
 Log.d(TAG,"a and c = " +a.and(c))
 Log.d(TAG,"a or c = " +a.or(c))
 Log.d(TAG,"a or c = " +(a or c))
 Log.d(TAG,"a inv = " +a.inv())
 Log.d(TAG,"a xor c = " +a.xor(c))
 Log.d(TAG,"a shl 2 = " +a.shl(2))
 Log.d(TAG,"d shr 2 = " +d.shr(2))
 Log.d(TAG,"d shr 2 = " +(d shr 2))
 Log.d(TAG,"d ushr = " +d.ushr(2))

运行结果

逻辑运算符

        逻辑运算符有三种,下表列出所有的逻辑运算符:

操作符描述
&&逻辑与。当且仅当两个操作数都为真,条件才为真。
||逻辑或。如果两个操作数的任何一个为真,条件为真。
!逻辑非。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算将得到false。

赋值运算符

        Kotlin语音支持以下赋值符:

操作符描述
=简单的赋值运算符,将右操作数的值赋给左侧操作数
+=加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数
-=减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数
*=乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数
/=除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数
%=取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数

 其他运算符

    is

        我们可以使用 is 运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)。

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做过类型判断以后,obj会被系统自动转换为String类型
    return obj.length 
  }

  // 这里的obj仍然是Any类型的引用
  return null
}

        或者 

fun getStringLength(obj: Any): Int? {
  if (obj !is String)
    return null
  // 在这个分支中, `obj` 的类型会被自动转换为 `String`
  return obj.length
}

        甚至还可以 

fun getStringLength(obj: Any): Int? {
  // 在 `&&` 运算符的右侧, `obj` 的类型会被自动转换为 `String`
  if (obj is String && obj.length > 0)
    return obj.length
  return null
}

   in 

        和区间组合在一起,主要表示在…区间。如果要表示不再某一区间,可以使用!in。

        可以用in判断数字是否在某个区间

// 检查x数值是否在1到4区间
if (x in 1..4){
}

        可以用in判断集合中是否存在某个元素 

// 检查list中是否有某个元素
if (name in list){
}

         可以用in遍历整个区间或者集合

// 遍历
for(i in 1..4){
    print(i)  // 1234
}

// 设置步长
for(i in 1..4 step 2) {
    print(i)  // 13
}

// for(i in 4..1)  // error
// 如果要从大到小遍历,可以使用downTo
for(i in 4 downTo 1 step 2) {
    print(i)  // 42
}

// until排除结束元素
for(i in 1 until 4) {
    print(i)  // 123
}

// 遍历list中的每个元素
for(item in list){}

条件控制

IF表达式

    传统用法

        该用法和Java一样,格式如下:

if(布尔表达式1){
    ...
}else if(布尔表达式2){
    ...
}
...
else if(布尔表达式n){
    ...
}
else{
    ...
}

        实例代码如下: 

  var a = 5
  var b = 6
  // 传统用法
  var max = a
  if (a < b) max = b

  // 使用 else 
  if (a > b) {
     max = a
  } else {
     max = b
  }

    赋值

        把要执行的IF语句块最后一句的值赋给一个变量,如果最后一条语句没有返回值,则返回为空。

var a = 5
var b = 6
val max = if (a > b) {
    print("Choose a")
            a
} else {
    print("Choose b")
    b
}

    使用区间

        使用in运算符来检测某个数字是否在指定区间内,区间格式为x..y。实例如下:

 val x = 5
 val y = 9
 if (x in 1..8) {
     println("x 在区间内")
 }

When表达式

        when将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。when既可以被当做表达式使用也可以被当做语句使用。如果它被当做表达式,符合条件的分支的值就是整个表达式的值。如果当做语句使用,则忽略个别分支的值。when类似其他语言中的switch操作。其最简单的形式如下:

var a = 5
when (a) {
    1 -> Log.d(TAG,"a == 1")
    2 -> Log.d(TAG,"a == 2")
    else -> { // 注意这个块
        Log.d(TAG,"a 不是 1 ,也不是 2")
    }
}

        在when中,else同switch的default。如果其他分支都不满足条件将会求值else分支。如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分割:

var a = 5
when (a) {
    0, 1 -> Log.d(TAG,"a == 0 or a == 1")
    else -> Log.d(TAG,"otherwise")
}

        我们也可以检测一个值在(in)或者不在(!in)一个区间或者集合中:

var a = 5
when (a) {
    in 1..10 -> Log.d(TAG,"x is in the range")
    !in 10..20 -> Log.d(TAG,"x is outside the range")
    else -> Log.d(TAG,"none of the above")
}

        我也可以用来检测一个值是(is)或者不是(!is)一个特定的类型的值。注意:由于智能转换,你可以访问该类型的方法和属性而无需 任何额外的检测。

fun hasPrefix(x:Any ){
    when(x) {
        is String -> x.startsWith("prefix")
        else -> false
    }
}

        when也可以用来取代if-else if链。如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:

var a = 5
var b = 6
when {
    a>b -> Log.d(TAG,"a > b")
    else ->  Log.d(TAG,"a < b")
}

when中也可以使用in运算符,用来判断集合内是否包含某实例:

val items = setOf("apple", "banana", "kiwi")
when {
    "orange" in items -> Log.d(TAG,"juicy")
    "apple" in items -> Log.d(TAG,"apple is fine too")
}

循环控制

for循环

        for循环可以对任何提供迭代器(iterator)的对象进行遍历,格式如下:

for(item in items) Log.d(TAG,item)

//或
for(item: Int in ints){
    //...
}

        如果你想要通过索引遍历一个数组或者一个list,你可以这样:

for (i in items.indices) {
    Log.d(TAG,items[i])
}

        这种“在区间上遍历”会编译成优化的实现而不会创建额外对象。或者你可以使用库函数withIndex:

for ((index, value) in items.withIndex()) {
    Log.d(TAG,"the element at $index is $value")
}

实例

val items = listOf("apple", "banana", "orange")

for (item in items) Log.d(TAG,item)

for (i in items.indices) {
    Log.d(TAG,items[i])
}

for ((index, value) in items.withIndex()) {
    Log.d(TAG,"the element at $index is $value")
}

结果

 while 与 do...while 循环

        while是最基本的循环,它的结构为:

while( 布尔表达式 ) {
  //循环内容
}

       对于while语句而言,如果不满足条件,则不能进入循环。但有的时候我们需要即使不满足条件,也至少执行一次,这是我们可以用 do...while。

        do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

do {
       //代码语句
}while(布尔表达式);

实例

Log.d(TAG,"----while 使用-----")
var x = 3
while (x > 0) {
    Log.d(TAG, (x--).toString())
}
Log.d(TAG,"----do...while 使用-----")
var y = 5
do {
    Log.d(TAG, (y--).toString())
} while(y>0)

结果

返回和跳转

返回关键字

        Kotlin和其他语言一样,有三个结构化跳转关键字:returnbreak和continue,三种关键的作用如下:

  • return:默认从最直接包围他的函数或者匿名函数返回。
  • break:终止最直接包围它的循环。
  • continue:继续下一次最直接包围它的循环。

        在循环中,kotlin支持传统的break和continue操作符。

for (i in 0..9) {
    if (i==3) continue  // i 为 3 时跳过当前循环,继续下一次循环
    Log.d(TAG,i.toString())
    if (i>5) break   // i 为 6 时 跳出循环
}

结果

标签跳转

        在kotlin中任何表达式都可以用标签(label)来标记。标记的格式为标识符后面加@符号,如:loop@,abc@,都是有效标签。要为一个表达式加标签,我们只要在其前面加标签即可。

break和continue标签

        标签限制的break跳转到刚好位于该标签指定的循环后面的执行点,而continue标签指定的是循环下一次迭代

        实例如下:

//break标签
Log.d(TAG,"break start")
loop@ for (i in 1..5) {
    for (j in 1..5) {
        if (i > 2 && j > 3) break@loop
        Log.d(TAG,"j = "+j)
    }
    Log.d(TAG,"i = "+i)
}
Log.d(TAG,"break end")

//continue标签
Log.d(TAG,"continue start")
loop@ for (i in 1..5) {
    for (j in 1..5) {
        if (i > 2 && j > 3) continue@loop
        Log.d(TAG,"j = "+j)
    }
    Log.d(TAG,"i = "+i)
}
Log.d(TAG,"continue end")

 运行结果如下:

2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: break start
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 4
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 5
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: i = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 4
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 5
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: i = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: break end
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: continue start
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 4
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 5
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: i = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 4
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 5
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: i = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 1
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 2
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: j = 3
2021-12-09 16:47:37.152 5040-5040/com.panda.kotlintest D/MainActivity: continue end

 非局部返回

         Kotlin有函数字面量、局部函数和对象表达式,因此Kotlin的函数可以被嵌套。标签限制的return允许我们返回到外层函数。最重要的一个用途就是从lambda表达式中返回。回想一下我们这么写的时候:

fun foo() {
    Log.d(TAG,"foo start")
    var ints =  listOf(1,2,3,0)
    ints.forEach {
        if (it == 0) return
            Log.d(TAG,it.toString())
        }
   Log.d(TAG,"foo end")
}

        这个 return 表达式从最直接包围它的函数即 foo 中返回。 (注意,这种非局部的返回只支持传给内联函数的 lambda 表达式。)

局部返回

        如果我们需要从 lambda 表达式中返回,我们必须给它加标签并用以限制 return。如下所示:

fun foo() {
    Log.d(TAG,"foo start")
    var ints =  listOf(1,2,3,0)
    ints.forEach lin@{
    if (it == 0) return@lin
        Log.d(TAG,it.toString())
    }
    Log.d(TAG,"foo end")
}

        现在,它只会从 lambda 表达式中返回。通常情况下使用隐式标签更方便。 该标签与接受该 lambda 的函数同名。

fun foo() {
    ints.forEach {
        if (it == 0) return@forEach
        Log.d(TAG,it.toString())
    }
}

        或者,我们用一个匿名函数替代 lambda 表达式。 匿名函数内部的 return 语句将从该匿名函数自身返回。

fun foo() {
    var ints =  listOf(1,2,3,0)
    ints.forEach(fun(value: Int) {
        if (value == 0) return
        Log.d(TAG,value.toString())
    })
}

标签返回值 

        当要返回一个值的时候,解析器优先选用标签限制的 return,代码如下:

var value =run loop@{
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@loop it //
        Log.d(TAG,"value = " +it)
    }
}

Log.d(TAG,"return value = " +value)

        意为"从标签 @loop 返回 it",而不是"返回一个标签标注的表达式 (@a it)"。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值