【Kotlin】Kotlin 基础语法:变量、控制和函数

变量

声明变量有两种方式 val 和 var,前者声明不可变变量,后者声明可变变量,Kotlin认为变量应首先考虑声明为 val,val 变量所指向的对象可变,这点与大部分高级编程语言类似。Kotlin 有优秀的类型推断机制,我们声明变量时应指定变量的值或变量的数据类型。

值得注意的是,声明数据类型的变量在使用前要被赋值,该检查属于编译期行为。我们如果使用 lateinit 关键字(仅可)声明可变变量则会委托到运行时进行,表示该变量在编译期无法证明是否初始化。常用于依赖注入框架等场景;成员变量不允许 1、2 形式的赋值方式,换句话说成员变量不允许在对象生成前尚未完成初始化,所以可以声明类型变量后在 init 块进行初始化。

kotlin 复制代码
val a = 1

1. val b: Int
   b = 2

2. var c = 3
   c = 4
   
3. 
   class cla {
       val d: Int
       init {
           d = 5
       }
   }

类型转换

Kotlin 的基本数据类型均有类包装,所以字面量可以调用函数。Kotlin 不允许隐式的类型转换(1),但允许字面量到目标类型的转换(3),显式进行类型转换的方式是使用 to 函数。

kotlin 复制代码
var a: Int = 1
1. var b: Long = a /* x */
2. var b: Long = a.toLong() /* √ */
3. var b: Long = 1.toLong() /* √ */

语句

Kotlin 的 while 循环语句和 Java 无异,for 循环语句使用 for-in 形式,访问集合的 in 前方变量会赋值成各集合元素,.. 、until 和 downTo 均能够生成区间,.. 生成的区间是全闭区间,until 生成的区间是左开右闭区间,downTo 生成的区间是倒序全闭区间,步长指区间每次迭代跳过的索引数,默认步长为 1,可以在表达式尾用 step 指定。

kotlin 复制代码
while (expression) { ... }

val arr = IntArray(5) /* 创建长度为5的Int数组 */

1. for (num in arr) { ... }

2. for (i in 0..arr.size - 1) { ... }

3. for (i in 0..arr.size - 1 step 2) { ... }

4. for (i in 0 until arr.size) { ... }

5. for (i in arr.size - 1 downTo 0) { ... }

if 语句和对标 Java Switch 的 When 语句都是表达式,能够返回符合条件代码块的最后 1 行表达式的值,使用方式是

kotlin 复制代码
fun max(a: Int, b: Int): Int = if (a > b) a else b

fun is10(c: Int): Boolean = when (c) {
    10 -> true
    else -> fal
} 

数组

Kotlin 有两种数组 Array 和 IntArray,分别对应 Java 层 Integer[] 和 int[] 两种数组,相互转换的底层逻辑是拷贝,分别会调用 toTypedArray 和 toIntArray 函数

kotlin 复制代码
val a = arrayOf(1, 2, 3)
val b = IntArray(5)

val c: Array<Int> = c.toTypedArray()
val d: IntArray = a.toIntArray()

函数

顶层函数

顶层函数是 Kotlin 针对不应从属于某个类的函数的设计,也就是工具类和入口类,我们能在 IDEA 的示例代码注意的,main 函数就是一个顶层函数,在 Java 层会将这些函数包裹在自动生成类中作为静态方法出现。

kotlin 复制代码
fun main() {
    val name = "Kotlin"
println("Hello, " + name + "!")

    for (i in 1..5) {
println("i = $i")
    }
}

顶层函数以 kt 文件为单位独立存在,通常自动生成类的类名为 kt 文件名,也可以通过注解自定义指定,该注解会默认为整个文件的所有顶层函数生成该类,且通常在不同文件声明相同的自动生成类名会致使命名冲突错误。

kotlin 复制代码
@file:JvmName("MathUtils")
fun add(a: Int, b: Int) = a + b

/* -> */

public final class MathUtils {
    /* 没有构造函数 */
    public static int add(int a, int b) {
        return a + b;
    }
}

顶层属性的概念和顶层函数类似,也会在自动生成类定义 private static 字段,同时会生成字段的 get 和 set 方法(如果属性为 val 则没有 set 方法)。顶层属性会在文件对应类第一次被加载时执行初始化操作。此外,如果希望以 public static final 形式将属性暴露给 Java,则可以使用 const 修饰所有的基本数据类型和 String,且该属性必须是 val 且要被适当初始化。

kotlin 复制代码
/* God.kt */
val name = "洪秀全"
const val rank = 2

/* -> */

public final class GodKt {
    private static final String name = "洪秀全";
    
    public static getName() {
        return name;
    }
    
    public static final int rank = 2;
}

扩展函数

Kotlin 的 API 相较于 Java 更加丰富,这不是通过魔改 Java API 来实现的,而是使用扩展函数,它就是某个类的成员函数,但是定义在该类的外面。扩展函数和顶层函数在 Kotlin 的地位等同,扩展函数在 Java 层也是静态方法,但扩展函数可以分为顶层扩展函数和成员扩展函数,二者的上下文范围不同,后者更局限一些,只能在所在类实例的上下文环境调用。

kotlin 复制代码
/* StringUtils.kt */
fun String.lastChar(): Char = this.get(this.length - 1)

/* -> */

public final class StringUtilsKt {
    public static char lastChar(String s) {
        return s.charAt(s.length() - 1);
    }
}

/* --- */

class SomeClass {
    fun String.lastChar(): Char = this.get(this.length - 1)
}

/* -> */

public final class SomeClass {
    public static char lastChar(SomeClass sc, String s) {
        return s.charAt(s.length() - 1);
    }
}

在顶层函数和扩展函数的介绍中不难注意到的点是,Kotlin 文件也有工程意义,区别于 Java 文件名与 public 顶级类类名对应的情况,Kotlin 文件可以包含多个非文件名的类和多个顶层函数或属性。

扩展属性可以视为以变量角度获得扩展函数值的方法,因为我们并没有直接修改扩展类的代码,所以扩展属性字段本身是不存在的,不能进行初始化,也没有默认 get 实现,要自定义 get 函数。

kotlin 复制代码
val String.lastChar: Char
    get() = get(length - 1)
    
/* -> */

public final class SomeClass {
    public static char getLastChar(String s) {
        return s.charAt(s.length() - 1);
    }
}

可变参数与中缀调用

Kotlin 可以用 mapOf 函数创建哈希表,类似 Java 的 asList,该函数传递的参数是可变的,可变性是通过 vararg 关键字修饰形式参数得到的,值得注意的是,Java 的可变函数可以传入数组,但 Kotlin 要求开发者显式解包数组,解包的方式是使用展开运算符 * 修饰对应参数。

使用 mapOf 构建哈希表会注意到, to 表示 key 到 value 的映射结构,这是特殊的函数调用,即中缀调用。一般 to 函数的调用形式如 3,返回 Pair<Int, String> 实例,中缀函数可以与唯一参数的函数共同使用,通过 infix 修饰符以声明中缀函数,to 函数是扩展函数,可以创建任意元素对,作为泛型接收者的扩展,其函数声明如 4。

kotlin 复制代码
/* mapOf的函数声明 */
1. public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V>

2. val map = mapOf(1 to "one", 2 to "two", 3 to "three")

3. 1.to("one")

4. infix fun Any.to(other: Any) = Pair(this, other)

5. 
fun main(args: Array<String>) {
    val list = listOf("args: ", *args)
    /* 相当于用"args: "和args的各参数建立集合 */
}
相关推荐
FunnySaltyFish4 小时前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
Kapaseker10 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z3 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton4 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream4 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam4 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker4 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
糖猫猫cc5 天前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
如此风景5 天前
kotlin协程学习小计
android·kotlin