Kotlin基础-基本语法

477 阅读2分钟

1、包的定义与导入

1)包的声明

包的声明在代码文件的开发,它的声明格式如下 package 包名

包名是在您工程根目录下的子目录,如下

5.png

这个蓝色的kotlin目录就是您此工程的根目录,您可以在File->Project Structure中看到,蓝色的Source称为源根目录

6.png

如下图,在根目录下创建 com.jetbrains 包,并在此包下创建 Demo1.kt 文件,文件中第一行就会默认为您声明包 package com.jetbrains

7.png

其实包在您的计算机中对应的就是目录,您可以修改您的包名

2)包的导入

包的导入的格式为 import 资源全名

刚刚我们在根目录下创建了 com.jetbrains 包,我们在Demo1.kt中加一个名为demo1的函数,这个demo1函数的全名为 com.jetbrains.demo1 ,函数后面会详细提到

com.jetbrains.demo1.kt

package com.jetbrains
​
fun main() {
    println("Demo1")
}
​
fun demo1() {
    println("demo1")
}

我们回到IDEA为我们默认创建的Main.kt文件下,在上方导入 com.jetbrains.demo1

Main.kt

import com.jetbrains.demo1
​
fun main(args: Array<String>) {
    demo1()
}

然后运行次程序您会看到控制台输出

demo1

kotlin会默认导入一些包,这些包您无需在上方通过import手动导入

2、程序入口

每一个kotlin程序都有一个执行入口,在单个kotlin文件中,main函数是执行入口

fun main() {
    println("Hello world!")
}

kotlin程序的入口函数允许传入可变数量的字符串参数,使用过Java的小伙伴可能清楚

fun main(args: Array<String>) {
    println(args.contentToString())
}

如上,它会将您在命令行的参数输出,比如

$ kotlin MainKt a b c
[a, b, c]

当然,在IDEA直接点击绿色的执行程序按钮不会有输出,您可以在您的工程目录下的 out/production/kotlin_start 找到MainKt.class字节码文件,进入此目录执行上述操作就好了

3、标准输入输出

print可以将打印到标准输出, println打印后换行

print("Hello, ")
print("World!")
​
println("Hello, World!")
println(123)
println(3.14)

readln读取一行,注意读取到的结果为String类型

val value = readln()

使用 toInt()可将其转为Int类型的数据,Kotlin中的基本数据类型后面会详细解释,除此之外还有 toLong(), toDouble(), toBoolean() 等等

val intValue = readln().toInt()
val longValue = readln().toLong()
val doubleValue = readln().toDouble()
val booleanValue = readln().toBoolean()

注意,如果您的版本是 Kotlin 1.6 之前,是用 readLine()!!

val value = readLine()!!

您可以使用 split 关键字来读取多个输入数据,比如用空格分割

val (a, b) = readln().split(" ")

4、函数

Kotlin中的函数使用关键字 fun 来定义,如下

fun sum(a: Int, b: Int): Int {
    return a + b;
}

上述函数sum接受两个Int类型的参数,返回值为Int类型

在Kotlin中函数可以是一个表达式,返回值可以自动推断

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

如果是不返回任何有意义的值,可以用 Unit 关键字

fun printSum(a: Int, b: Int): Unit {
    println("$a$b的和为: ${a + b}")
}

如果是 Unit 可以省略

fun printSum(a: Int, b: Int) {
    println("$a$b的和为: ${a + b}")
}

参数还可以有默认值,用来初始化,如下示例,如果您不传入第二个参数,它默认是0

fun sum(a: Int, b: Int = 0): Int {
    return a + b;
}

可以在其他函数中调用此函数,如下在main函数中调用sum函数

fun main() {
    val res = sum(1, 2)
    println(res)
}

区别不同函数不止有函数名一种方式,需要通过函数名和参数列表来确定,如下是三个不同的函数

fun sum(a: Int): Int {
    return a
}
​
fun sum(a: Int, b: Int): Int {
    return a + b
}
​
fun print(a: Int, b: Int): Unit {
    println("a = $a, b = $b")
}

我们可以在其他函数中调用这三个函数

fun main() {
    val a = sum(1)
    println(a)
    val b = sum(1, 2)
    println(b)
    print(1, 2)
}

函数的调用会涉及到一个入栈、出栈操作,遵循先入后出的原则,可以由下图来理解

13.png

5、变量

使用val关键字定义只读变量,只读变量赋值后不可更改,但并不是意味着您声明之后就要立刻赋值,您可以定义变量时先声明数据类型,等需要时再进行赋值

fun main() {
    val a: Int = 1 // 声明后立刻赋值
    val b = 2 // 自动推断类型
    val c: Int // 未提供初始值,先声明类型
    c = 3 // 延后赋值
    println("a = $a, b = $b, c = $c")
}

使用var关键字定义可变变量,进行赋值操作之后可以重新赋值

fun main() {
    var a = 1
    a += 1
    println("a = $a")
}

其实val a = 1翻译成Java的代码就是private final Int a = 1var a = 1翻译成Java代码就是private Int a = 1,只不过Kotlin中使用val关键字更加的简洁

这里需要注意的是,val只是让变量为可读,如果变量是一个引用,那么引用的对象中的属性还是可以修改的

其实Kotlin官方还是多推荐我们使用val关键字来声明变量

我们应该优先使用val来避免副作用

引用水滴团队的《Kotlin核心编程》一书中的理解:尽可能采用val、不可变对象及纯函数来设计程序

当然也有很多场景下我们不得不需要使用var来声明变量,您现阶段无需有过多心智负担,秉持优先使用val的原则即可

6、基本数据类型

14.png

(1)数值类型(Number)

Kotlin中的数值类型分为两种,分别是整型(Integer types)和浮点型(Floating-point types)

类型大小最小值最大值
Byte8bits(1Byte)-128127
Short16bits(2Byte)-3276832767
Int32bits(4Byte)-2,147,483,648(231-2^{31})2,147,483,647 (23112^{31}-1)
Long64bits(8Byte)-9,223,372,036,854,775,808 (263-2^{63})9,223,372,036,854,775,807 (26312^{63}-1)
类型大小有效位指数位小数数位
Float32bits(4Byte)2486-7
Double64bits(8Byte)531115-16

以上类型都是Kotlin中封装的数值类型,它们都继承自Number类,我们其实可以在源码中看到

10.png

对于整型变量

如果您在初始化变量的时候未显式指定数据类型,编译器会自动推断,如整形,默认会为您初始化为Int类型,如果您的值超过了Int类型的范围,它将自动转化为Long类型,可以通过is关键字来判断

val int = 1 // Int类型
val long = 2147483648 // Long类型
println(long is Long) // true

Long类型的可以通过添加L后缀的方式显式指定

val long = 2147483648L // Long类型

默认会是Int类型,您也可以通过显式声明的方式去指定类型

val byte: Byte = 1 // Byte类型

当然如果您如果显式声明后赋值超过类型所限定的范围,它会在编译器给出您错误提示,在Intellij IDEA中会在您写代码的时候就给出提示

8.png

Kotlin中也提供了无符号整型,这里不过多阐述,下表列出类型名称以及数据范围

类型数据范围
UByte0-255
UShort0-65535
UInt0-23212^{32}-1
ULong0-26412^{64}-1

对于浮点型变量

如果您在初始化变量的时候未显式指定数据类型,编译器会自动推断,如浮点型,默认会为您初始化为Double类型,当然您也可以通过添加f(F)后缀的方式去显式指定

val double = 1.0 // Double类型
val float = 1.0f // float类型

但是您初始化的时候如果显式指定浮点类型却赋值为整型会有错误提示

9.png

JVM中的数字表示

在Kotlin中,==用于比较对象结构,而===用于比较对象引用

如果您创建一个可为空的数字引用

val a = 128
val b: Int? = a
val c: Int? = a
println(b == c) // true
println(b === c) // false

但如果您的值在-128~127这个范围区间内,对象引用是相同的,这是因为JVM对-128~127之间的Integer类型做了内存优化

val a = 127
val b: Int? = a
val c: Int? = a
println(b == c) // true
println(b === c) // true

类型转换

前面已经介绍过几种类型转换的方式了,toInt(), toDouble()等等,这里暂时不过多阐释,比如sqrt()函数就需要传入浮点型

val num = 100
val res: Double = sqrt(num.toDouble())

(2)布尔类型

布尔类型的值只有true和false两种,布尔值可以空

val a: Boolean = true
val b = false
val c: Boolean? = null
println(a && b) // false
println(a || b) // true

(3)字符类型

区别于Java,Kotlin中字符类型不属于数值类型,不能与数字互操作

val a: Char = 'a'
val b = 'b'
val c = '\n'
print(a)
print(c)
print(b)

code属性可以得到此字符的ASCII编码

val a = 'a'
println(a.code) // 97

(4)字符串类型

最简单的形式,字符串类型是用""来表示

val s: String = "I'm a coder"
println(s)

简单介绍字符串类型的几个特性

可以用in关键字判断某个字符是否出现在此字符串中,也可以通过此关键字来遍历这段字符串

val c = 'I'
val s: String = "I'm a coder"
println(c in s) // true
for (c in s) {
    println(c)
}

可以通过uppercase()方法将字符串全转换为大写

println("abcd".uppercase()) // ABCD

可以通过+来连接字符串

val a = "abcd"
val b = a + "def"
println(b)

可以通过""" """来使用原始字符串,它不处理转义,可以包含换行符和任意其他字符,并且可以通过trimMargin()去掉前导空格

val s = """
    #include <iostream>
​
    using namespace std;
​
    int main() {
        cout << "Hello, World!" << endl;
        return 0;
    }
""".trimIndent()
println(s)

字符串模版

val i = 1
println("i = $i") // i = 1val s = "abc"
println("s.length = ${s.length}") // s.length = 3

(5)数组类型

在Kotlin中,一切皆为对象,类与对象后面会详细提及,数组在Kotlin中就是由Array类来表示的,它有get()和set()函数

在这里我们只需要知道数组类型如何表示和遍历即可

数组的定义我们可以通过arrayOf或者Array的构造函数的方式,遍历我们可以通过Array类的forEach()方法

val a: Array<String> = arrayOf("a", "b", "c")
val b: Array<Int> = arrayOf(1, 2, 3)
val c = Array(5) { i -> (i * i).toString() }
​
a.forEach { println(it) }
b.forEach { println(it) }
c.forEach { println(it) }

Array类有size属性,您可以通过它得到您数组的长度

(6)任意类型

Kotlin中还有Any类型,您可以通过以下的方式去转换

val s: Any = "Hello"
if (s is String) {
    println(s.length)
}

或者

val s: Any = "Hello"
if (s !is String) return
println(s.length)

请看以下示例,可以通过一个函数来检查传入参数的类型,when表达式是Kotlin中的一个语法糖,后面还会详细提及

fun check(value: Any): String =
    when (value) {
        is Byte -> "Byte"
        is Short -> "Short"
        is Int -> "Int"
        is Long -> "Long"
        is Float -> "Float"
        is Double -> "Double"
        is Boolean -> "Boolean"
        is Char -> "Char"
        is String -> "String"
        else -> "Unknown"
    }
​
fun main() {
    println(check("Hello")) // String
}

(7)类型的检查和强制转换

最后就是类型的检查和强制转换

类型的检查可以通过is关键字来完成

val s = "Hello"
println(s is String)

不安全类型转换 ​ 如下,y的值为null,如果强制转换为String类型是会抛异常的

val y = null
val x: String = y as String

在Kotlin中,加上可空类型就可以避免出现异常,转换失败后随机返回null,这也是Kotlin中值得夸赞的一个地方

val y = null
val x: String? = y as String?
println(x) // null

7、条件判断、循环语句

if判断条件

以下是if条件语句的一个基本形式

val a = 1
val b = 2
var max = a
if (a > b) {
    max = a
} else {
    max = b
}

在Kotlin中没有三元运算符,if语句可以作为表达式使用,如下

val a = 1
val b = 2
val max = if (a > b) a else b

在if表达式中分支是块,如下,最后一个块是您表达式返回的值,最后返回的值是b,而中间还可以做一些其他的操作,比如打印

val a = 1
val b = 2
val max = if (a > b) {
    println(a)
    a
} else {
    println(b)
    b
}

if条件判断语句可以搭配in关键字一起使用

if (1 in 1..10) println("Yes")
else println("No")

When表达式

Kotlin中没有switch,取而代之的是when表达式,when表达式的表达能力更强,上面我们已经接触过一次,下面我们看when表达式如何使用

我们的when表达式会将参数匹配,然后执行相应的操作,如下,x参数匹配到了1,就执行println(1)操作,那如果所有的分支都没有匹配上就会走else分支

val x: Int = 1
when (x) {
    1 -> println(1)
    2 -> println(2)
    else -> println("No conditions to match")
}

when表达式还有很多玩法,我们简单拓展一点

您可以通过,多值匹配

val x: Int = 1
when (x) {
    1, 2 -> println("1 or 2")
    else -> println("No conditions to match")
}

when表达式还可以传入函数,匹配函数的返回值

fun getNum(x: Int) = x * 2fun main() {
    when (getNum(2)) {
        2 -> println(2)
        4 -> println(4)
        else -> println("No conditions to match")
    }
}

when表达式匹配的值中可以使用isin关键字,匹配is关键字在上面有示例

fun getNum(x: Int) = x * 2fun main() {
    when (getNum(2)) {
        in 1..2 -> println("1..2")
        in 3..4 -> println("3..4")
        else -> println("No conditions to match")
    }
}

还可以作为函数返回值使用,在Any类型处我们演示过

for循环与while循环

学习过其他编程语言的对这两个肯定不陌生,那在Kotlin中其实for循环有很多遍历的方式

for (i in 1..10) {
    println(i)
}
// 以下输出结果为0246
for (i in 0 to 6 step 2) {
    print(i)
}
// 以下输出结果为6420
for (i in 6 downTo 0 step 2) {
    print(i)
}

for循环可以用来遍历一个Array对象

val array: Array<Int> = arrayOf(1, 2, 3, 4)
for (i in array) {
    println(i)
}

或者通过另一种方式

val array: Array<Int> = arrayOf(1, 2, 3, 4)
for (i in array.indices) {
    println(array[i])
}

或者使用withIndex,同时拿到下标和值

val array: Array<Int> = arrayOf(1, 2, 3, 4)
for ((index, value) in array.withIndex()) {
    println("$index -> $value")
}

通过breakcontinue关键字可以终止循环和跳过此次循环

val array: Array<Int> = arrayOf(1, 2, 3, 4)
for ((index, value) in array.withIndex()) {
    if (index == 3) break
    println("$index -> $value")
}
​
for ((index, value) in array.withIndex()) {
    if (index == 2) continue
    println("$index -> $value")
}

while循环就不过多阐释了

var x = 3
while (x > 0) {
    println(x)
    x--
}
​
var y = 3
do {
    println(y)
    y--
} while (y > 0)

文章若有错误或不足之处,欢迎大家评论区指正,谢谢大家!

另外,欢迎大家来了解一下济南KUG(Jinan Kotlin User Group),如果您对Kotlin技术分享抱有热情,不妨加入济南KUG,济南KUG官网:济南KUG