【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的各参数建立集合 */
}
相关推荐
Rysxt_12 小时前
Kotlin前景深度分析:市场占有、技术优势与未来展望
android·开发语言·kotlin
莫白媛12 小时前
Android开发之Kotlin 在 Android 开发中的全面指南
android·开发语言·kotlin
天勤量化大唯粉1 天前
基于距离的配对交易策略:捕捉价差异常偏离的均值回归机会(天勤量化代码实现)
android·开发语言·python·算法·kotlin·开源软件·策略模式
hudawei9961 天前
kotlin冷流热流的区别
android·开发语言·kotlin·flow··冷流·热流
hudawei9962 天前
对比kotlin和flutter中的异步编程
开发语言·flutter·kotlin·异步·
モンキー・D・小菜鸡儿2 天前
Android11 新特性与适配指南
android·kotlin·安卓新特性
starrycode8882 天前
【每日一个知识点】Kotlin基础语法核心学习笔记
笔记·学习·kotlin
alexhilton3 天前
学会在Jetpack Compose中加载Lottie动画资源
android·kotlin·android jetpack
用户69371750013843 天前
29.Kotlin 类型系统:智能转换:类型检查 (is) 与类型转换 (as)
android·后端·kotlin