kotlin入门>1-基础语法

概述:

语言学习,以实用为主,少扯淡,开门见山
概述详见:https://www.kotlincn.net/docs/reference/server-overview.html

一、定义与概念:

1、程序入口点:

kotlin 应用程序的入口点事main 函数:

1
2
3
fun main() {
println("Hellow world!")
}

2、变量:

2.1、不可变变量:

关键字:val

只能为其赋值一次,相当于Java 中的 final

1
2
3
4
5
val a: Int = 1  // 立即赋值
val b = 2 // 自动推断出 `Int` 类型

val c: Int // 如果没有初始值类型不能省略
c = 3 // 明确赋值

2.1、可变变量:

关键字:var

可重新赋值。

1
2
var x = 5 // 自动推断出 `Int` 类型
x += 1 //6

3、注释:

与大多数现代语言一样,Kotlin 支持单行(或行末)与多行(块)注释。

1
2
3
4
5
6
7
8
// 这是一个行注释

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

/* 注释从这里开始
/* 包含嵌套的注释 */
并且在这里结束。 */

4、字符串模板:

通过在字符串中使用$ 符号来引用变量。

1
2
3
4
5
6
7
var a = 1
// 模板中的简单名称:
val s1 = "a is $a" // A is 1

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

二、基本类型:

1、数字

1.1、整型

数字对比

tip:所有以未超出Int 最大值的整型值初始化的变量都会推断为Int 类型。如果初始值超过了其最大值,那么推断为Long,若显示指定Long 型值,则请在该值后追加lL

1.2、浮点型

数字对比

tip:对于以小数初始化的变量,编译器会推断为Double 类型,如需将一个值显示指定为Float 类型,需添加 fF 后缀。若这样的值包含多于6 ~7 位十进制数,那么会将其舍入。

注:

  • 根据 IEEE 754 标准, 两种浮点类型的十进制位数(即可以存储多少位十进制数)不同。 Float 反映了 IEEE 754 单精度,而 Double 提供了双精度
  • kotlin中的数字没有隐式拓宽转换(可使用显示转换),例:
    1
    2
    3
    4
    5
    6
    7
        val i = 1    
    val d = 1.1
    val f = 1.1f

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

1.3、显示转换:

1
2
val b: Byte = 1
val i = Int = b.toInt();

每个数字类型支持如下的转换:

  • toByte(): Byte
  • ttoShort(): Short
  • ttoInt(): Int
  • ttoLong(): Long
  • ttoFloat(): Float
  • ttoDouble(): Double
  • ttoChar(): Char

运算转换:

1
val l = 1L + 3 // Long + Int => Long

1.4、字面常量:

整数:

  • 十进制:123。Long类型:123L
  • 十六进制:0x0F
  • 二进制:0b00001011
  • 八进制:不支持

浮点数:

  • 默认double:123.5123.5e10
  • Float用 fF 标记:123.5f

2、字符 Char

表示:

  • 字符字面值用单引号括起来,'1'
  • 转义字符::\t\b\n\r\'\"\\\$
  • 编码其他字符要用 Unicode 转义序列语法:'\uFF00'

字符

3、布尔 Boolean

布尔

4、数组 Array

4.1、创建数组:

1
2
3
4
val testArr = arrayOf(1, 2, 3, 4, 5)  //[1, 2, 3, 4, 5]
val testArrNull = arrayOfNulls<String>(5) //[null, null, null, null, null]

val arr = Array(5) { i -> (i*i).toString() } //0, 1, 4, 9, 16

4.2、原生类型数组:

如:ByteArrayShortArrayIntArray
注:Array 没有继承关系。

1
2
3
4
5
val x: IntArray = intArrayOf(1, 2, 3)  //[1, 2, 3]

val arr1 = IntArray(5) //[0, 0, 0, 0, 0]
val arr2 = IntArray(5) { 42 } //[42, 42, 42, 42, 42]
val arr3 = IntArray(5, { it*1 }) //[0, 1, 2, 3, 4]

4.3、属性函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fun main(args: Array<String>) {
val array1 = arrayOf(1,2,3,4)
array1.set(0,5)
array1[2] = 6
for(element in array1){
printl(element) //5,2,6,4
}

val array2 = arrayOf<Long>(11,12,13,14)
array2.set(2,10)
array2[3] = 8
for(element in array2){
print(element) //11,12,10,8
}
}

5、字符串 String

5.1、表示:

  • 用String 类型表示,不可变
  • 使用 + 操作符连接字符串
  • 原始字符串:用三个双引号表示:"""
    1
    2
    3
    4
    val text = """
    for (c in "foo")
    print(c)
    """
  • 去除前导空格:
    默认 | 用作边界前缀,但你可以选择其他字符并作为参数传入,比如 trimMargin(">")
    1
    2
    3
    4
    5
    6
    val text = """
    |Tell me and I forget.
    |Teach me and I remember.
    |Involve me and I learn.
    |(Benjamin Franklin)
    """.trimMargin()

5.2、字符串模板:

  • 表示:$
    1
    2
    3
    4
    5
    6
    7
    //变量
    val i = 10
    println("i = $i") // 输出“i = 10”

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

原始字符串与转义字符串内部都支持模板。 如果你需要在原始字符串中表示字面值 $ 字符(它不支持反斜杠转义)

1
2
3
val price = """
${'$'}9.99
"""

5.3、属性:

字符串属性

1
2
3
4
5
6
fun foo() {
val s1 = "hello world"
println(s1.length) //11
println(s1.indices) //0..10
println(s1.lastIndex) //10
}

5.4、函数:

字符串函数


三、运算符

  • 算术运算符
  • 关系运算符
  • 赋值运算符
  • 一元运算符
  • 按位运算
  • 逻辑运算符

1、算术运算符

算术运算符

2、关系运算符

关系运算符

3、赋值运算符

赋值运算符

4、一元运算符

一元运算符

5、逻辑运算符

逻辑运算符

6、按位运算

按位运算

1
2
3
4
5
6
7
8
9
10
11
12
13
fun main(args: Array<String>){  
var a=10 // 10 = 2^3 + 2^0 + 2^1 + 2^0 --> 1010
var b=2

println("a.shl(b): "+a.shl(b)) //a.shl(b): 40;末尾补2个0
println("a.shr(b): "+a.shr(b)) //a.shr(b): 2;去掉末尾两位
println("a.ushr(b:) "+a.ushr(b)) //a.ushr(b:) 2;
println("a.and(b): "+a.and(b)) //a.and(b): 2
println("a.or(b): "+a.or(b)) //a.or(b): 10
println("a.xor(b): "+a.xor(b)) //a.xor(b): 8
println("a.inv(): "+a.inv()) //a.inv(): -11

}

四、包与导入

五、控制流程

1、if

在 Kotlin 中,if是一个表达式,即它会返回一个值。 因此就不需要三元运算符(条件 ? 然后 : 否则),因为普通的 if 就能胜任这个角色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 传统用法
var max = a
if (a < b) max = b

// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}

// 作为表达式
val max = if (a > b) a else b

//代码块
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}

2、when

when 取代了类 C 语言的 switch 操作符。

when 既可以被当做表达式使用,也可以被当做语句使用

  • 作为表达式:符合条件的分支的值,就是整个表达式的值。必须有else分支。(枚举enum类和密封sealed类子类型 可不用)
  • 作为语句:忽略个别分支的值。

2.1、示例

  • 变量赋值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    val x = 10;
    val s = "5"

    val a =
    when(x) {
    parseInt(s) -> print("s encodes x")
    0, 1 -> print("x == 0 or x == 1")
    in 6..8 -> print("x is in the range")
    else -> print("otherwise")
    }
  • 函数表达式:

    1
    2
    3
    4
    fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
    }
  • 取代 if-else if
    如果不提供参数,所有的分支条件都是简单的布尔表达式,而当一个分支的条件为真时则执行该分支:

    1
    2
    3
    4
    5
    when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
    }

3、for

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

for 可以循环遍历任何提供了迭代器的对象。即:

  • 有一个成员函数或者扩展函数 iterator(),它的返回类型
  • 有一个成员函数或者扩展函数 next(),并且
  • 有一个成员函数或者扩展函数 hasNext() 返回 Boolean。

这三个函数都需要标记为 operator。

示例:

  • 对区间或者数组的 for 循环会被编译为并不创建迭代器的基于索引的循环。

    1
    2
    3
    4
    5
    6
    for (i in 1..3) {
    println(i)
    }
    for (i in 6 downTo 0 step 2) {
    println(i)
    }
  • 通过索引遍历一个数组或者一个 list

    1
    2
    3
    for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
    }

4、while

whiledo..while 照常使用

1
2
3
4
5
6
7
while (x > 0) {
x--
}

do {
val y = retrieveData()
} while (y != null) // y 在此处可见

5、返回、跳跃

Kotlin中有三个跳跃表达式。 这些跳转表达式用于控制程序执行的流程。 这些跳跃语句是:

  • break:终止最直接包围它的循环。
  • continue:继续下一次最直接包围它的循环。
  • return:默认从最直接包围它的函数或者匿名函数返回。
1
val s = person.name ?: return

5.1、标签

  • break、continue
    在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@fooBar@都是有效的标签(参见语法)。 要为一个表达式加标签,我们只要在其前加标签即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    loop@ for (i in 1..100) {
    for (j in 1..100) {
    if (j==50) {
    break@loop
    } else if(j==60) {
    continue@loop
    }
    }
    }
  • return
    没有标签则结束(foo)函数
    通常情况下使用隐式标签更方便。 该标签与接受该 lambda 的函数同名。

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

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

当要返一个回值的时候,解析器优先选用标签限制的 return,即
return@a 1
意为“从标签 @a 返回 1”,而不是“返回一个标签标注的表达式 (@a 1)”。
如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun foo(ints: List<Int>): List<String> {
val result = ints.map f@{
if (it == 0) return@f "zero" //返回的是"zero"
if (it == -1) return emptyList() //返回到foo函数
"number $it" //else,继续遍历
}
print(result)
return result
}

fun main(args : Array<String>){
foo(listOf(1, -1, 1)) // []
foo(listOf(1, 0, 1)) // ["number 1", "zero", "number 1"]
}
-------------我是有底线的-------------