kotlin基础——>基本数据类型、控制流、返回和跳转

1.对于数字的定义,支持java 8的下划线分割的方式

val a = 1_2_3 与 val a = 123 是相同的

2.如果要指定数字类型有两种方式

val a : Float = 1
或者
val a = 1f

3.kotlin没有隐式拓宽转换

val i = 1 
val d = 1.1
val f = 1.1f

printDouble(d)
printDouble(i) // 错误:类型不匹配 
printDouble(f) // 错误:类型不匹配

4.kotlin数字定义不支持八进制

十进制:     123
   -- Long类型 123L
十六进制:  0x0f
二进制:     0b001

5.当采用可空的引用(Int?)或泛型,后者情况会把数字装箱,装箱的数字保留相等性,但不一定保留同一性

val a: Int = 10000
println(a === a) // 输出“true”
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA === anotherBoxedA) // !!!输出“false”!!!

但保留相等性
val a: Int = 10000
println(a == a) // 输出“true”
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA == anotherBoxedA) // 输出“true”

6.显示转换,现在无法直接用long类型接收一个int类型的数字,在早起版本会把int类型装箱变为Long类型,后续版本在编译期就会报错,无法通过默认方式的编译成功

// 假想的代码,实际上并不能编译:
val a: Int? = 1 // 一个装箱的 Int (java.lang.Integer)
val b: Long? = a // 隐式转换产生一个装箱的 Long (java.lang.Long)
print(b == a) // 惊!这将输出“false”鉴于 Long 的 equals() 会检测另一个是否也为 Long

//以下的方式也是错的
 val b: Byte = 1 // OK, 字面值是静态检测的
 val i: Int = b // 错误


但是可以通过显式转换
 val i: Int = b.toInt() // OK:显式拓宽

可以使用以下的方式
— toByte(): Byte
— toShort(): Short
— toInt(): Int
— toLong(): Long
— toFloat(): Float
— toDouble(): Double 
— toChar(): Char

注意:
val l = 1L + 3 // Long + Int => Long

7.运算时,整数计算只会得到整数,如果需要返回浮点,需要其中一个进行显式转换

 val x = 5 / 2.toDouble() 
 println(x == 2.5)

8.位运算,对于位运算,没有特殊字符来表示,而只可用中缀方式调用具名函数

val x = (1 shl 2) and 0x000FF000 

这是完整的位运算列表(只用于 Int 与 Long):

— shl(bits) ‒ 有符号左移
— shr(bits) ‒ 有符号右移
— ushr(bits) ‒ 无符号右移
— and(bits) ‒ 位与
— or(bits) ‒ 位或
— xor(bits) ‒ 位异或
— inv()‒位非

9.区间比较

区间实例以及区间检测:a..b、x in a..b、x !in a..b

10.字符Char,不能直接作为数字,可以显式转换

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


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

11.数组,在kotlin中使用Array类来表示,在kotlin中是不型变的(invariant)。这意味着 Kotlin 不让我们把 Array<String> 赋值给Array<Any>,以防止可能的运行时失败(但是你可以使用 Array<out Any>,参⻅类型投影)。

// 创建一个 Array<String> 初始化为 ["0", "1", "4", "9", "16"] 
val asc = Array(5) { i -> (i * i).toString() }
asc.forEach { println(it) }

12.原生类型数组

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

// 大小为 5、值为 [0, 0, 0, 0, 0] 的整型数组 
val arr = IntArray(5)

// 例如:用常量初始化数组中的值
// 大小为 5、值为 [42, 42, 42, 42, 42] 的整型数组 
val arr = IntArray(5) { 42 }

// 例如:使用 lambda 表达式初始化数组中的值
// 大小为 5、值为 [0, 1, 2, 3, 4] 的整型数组(值初始化为其索引值) 
var arr = IntArray(5) { it * 1 }

13.无符号整型(kotlin 1.3起才可用)

val a :UByte = 1u
val b: Byte = a.toByte()

注意:将类型从无符号类型更改为对应的有符号类型(反之亦然)是二进制不兼容变更
无符号类型是使用另一个实验性特性(即内联类)实现的。

14.特化的类

与原生类型相同,每个无符号类型都有相应的为该类型特化的表示数组的类型:
— kotlin.UByteArray : 无符号字节数组
— kotlin.UShortArray : 无符号短整型数组
— kotlin.UIntArray : 无符号整型数组
— kotlin.ULongArray : 无符号⻓整型数组
与有符号整型数组一样,它们提供了类似于 Array 类的 API 而没有装箱开销。
此外,区间与数列也支持 UInt 与 ULong(通过这些类 kotlin.ranges.UIntRange 、 kotlin.ranges.UIntProgression 、kotlin.ranges.ULongRange 、 kotlin.ranges.ULongProgression )

 15.无符号是实验性的,如果要使用需要加入声明

— 如需传播实验性,请以 @ExperimentalUnsignedTypes 标注使用了无符号整型的声明。
— 如需选择加入而不传播实验性,要么使用 @OptIn(ExperimentalUnsignedTypes::class) 注解标注声明,
要么将 -Xopt-in=kotlin.ExperimentalUnsignedTypes 传给编译器。

 16.字符串关于"""(原始字符串)以及trimMargin()的使用

val text = """
            |Tell me and I > forget.
            |Teach me and I > remember.
            |Involve me and > I learn.
            |(Benjamin Franklin) """

println(text)

输出结果(上下的换行,和前面的空格都是):
  

            |Tell me and I > forget.
            |Teach me and I > remember.
            |Involve me and > I learn.
            |(Benjamin Franklin) 


val text = """
            |Tell me and I > forget.
            |Teach me and I > remember.
            |Involve me and > I learn.
            |(Benjamin Franklin) """.trimMargin()

println(text)

输出结果:

Tell me and I > forget.
Teach me and I > remember.
Involve me and > I learn.
(Benjamin Franklin) 

注意:trimMargin() 函数为去除前导空格,默认以 | 作为边界前缀,所以等同于trimMargin("|") ,边界前缀可以自己定义

17.字符串模版,可以直接使用 $ 符号

 val i = 10
 println("i = $i") // 输出“i = 10”


 val s = "abc"
 println("$s.length is ${s.length}") // 输出“abc.length is 3”

18.包导入,于java基本相同,对于出现名字冲突的可以使用as另外定义一个名字来取消冲突和歧义

import org.example.Message // Message 可访问
import org.test.Message as testMessage // testMessage 代表“org.test.Message”

19.在kotilin中if为一个表达式,可以返回一个值,也就是说对于三元运算符的写法,也可以用if替代,当然如果使用if作为表达式,那么必须要有else分支

 1 //传统用法
 2 var max: Int 
 3 if (a > b) {
 4     max = a 
 5 } else {
 6     max = b
 7 }
 8 
 9 
10 // 作为表达式
11 val max = if (a > b) a else b
12 
13 //或者写作
14 val max = if (a > b) {
15      print("Choose a")
16      a
17 } else { 
18     print("Choose b")
19      b
20 }

 

20.when取代了之前的switch,同样如果用于作为表达式,必须要有else分支,以下为when的几种写法

 1 when (x) {
 2     1 -> print("x == 1") 
 3     2 -> print("x == 2") 
 4     else -> { // 注意这个块
 5         print("x is neither 1 nor 2")
 6     }
 7 }    
 8 
 9 
10 //多条件相同处理时,用 , 分割
11 when (x) {
12     0, 1 -> print("x == 0 or x == 1") 
13     else -> print("otherwise")
14 }
15 
16 //可以用任意表达式作为分支,而不仅仅是常量
17 when (x) {
18     parseInt(s) -> print("s encodes x") 
19     else -> print("s does not encode x")
20 }
21 
22 //也可以检测一个值在(in)或者不在(!in)一个区间或者集合中
23 when (x) {
24     in 1..10 -> print("x is in the range")
25     in validNumbers -> print("x is valid")
26     !in 10..20 -> print("x is outside the range") 
27     else -> print("none of the above")
28 }
29 
30 //另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意:由于智能转换,你可以访 问该类型的方法与属性而无需任何额外的检测。
31 
32 fun hasPrefix(x: Any) = when(x) {
33         is String -> x.startsWith("prefix") 
34         else -> false
35 }       
36 
37 //when 也可以用来取代 if-else if链
38 when {
39      x.isOdd() -> print("x is odd")
40      y.isEven() -> print("y is even") 
41      else -> print("x+y is even.")
42 }
43 
44 //自kotlin 1.3起,可以使用以下语法将 when 的主语(subject,译注:指 when 所判断的表达式)捕获到 变量中:
45 
46 fun Request.getBody() =
47         when (val response = executeRequest()) {
48                 is Success -> response.body
49                 is HttpError -> throw HttpException(response.status) 
50 }
51     
52 注意:在 when 主语中引入的变量的作用域仅限于 when 主体。

21.for循环,可以对任何提供迭代器(iterator)的对象进行遍历,这相当于像 C# 这样的语言中的 foreach 循环

 1 // 1. 基本语法
 2 for (item in collection) print(item)
 3 
 4 //2.循环体是一个代码块
 5 for (item: Int in ints) {
 6      // ......
 7 }
 8 
 9 //说明:for 可以循环遍历任何提供了迭代器的对象。即:
10 //     — 有一个成员函数或者扩展函数 iterator(),它的返回类型
11 //     — 有一个成员函数或者扩展函数 next(),并且
12 //     — 有一个成员函数或者扩展函数 hasNext() 返回 Boolean 。
13 // 这三个函数都需要标记为 operator 
14 
15 //3. 使用数字区间迭代
16 for (i in 1..3) { 
17     println(i)
18 }
19 for (i in 6 downTo 0 step 2) {
20     println(i) 
21 }
22 
23 // 说明:对区间或者数组的 for 循环会被编译为并不创建迭代器的基于索引的循环。
24 
25 //4.如果想要通过索引遍历一个数组或者list,你可以这么做:
26 for (i in array.indices) {
27      println(array[i])
28 }
29 
30 //4.1 或者使用库函数 withIndex
31 for ((index, value) in array.withIndex()) {
32      println("the element at $index is $value")
33 }

22.while循环,这个没什么变化,于java相同

while (x > 0) {
   x--
}
do {
   val y = retrieveData()
} while (y != null) // y 在此处可⻅

23.在kotlin中break和continue增加了指定标签的方式,类似于C的写法,标签的格式为 标识符后跟@符号,例如 abc@

loop@ for (i in 1..100) {
        for (j in 1..100) {
            if (......) break@loop 
        }
}

24.return也可以采用标签返回的方式,这种方式主要是为了更好的应用于lambda表达式中

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        if (it == 3) return@lit // 局部返回到该 lambda 表达式的调用者,即forEach 循环
        print(it) 
    }
    print(" done with explicit label") 
}

//当然也可以使用隐式标签,该标签于接受该lambda的函数同名
  fun foo() {
     listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach // 局部返回到该 lambda 表达式的调用者,即 forEach 循环
        print(it)
     }

     print(" done with implicit label")

  }

 

  //或者用一个匿名函数替代lambda表达式,这样return返回的是匿名函数自身

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

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

return@a 1
//意为“返回 1 到 @a ”,而不是“返回一个标签标注的表达式 (@a 1) ”

 

 

 

 

posted @ 2020-06-18 17:53  王世桢  阅读(490)  评论(0编辑  收藏  举报