【Android】Kotlin教程(1)

文章目录

1.声明变量

可变变量定义:var 关键字

kotlin 复制代码
var a:Int = 1

不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)

kotlin 复制代码
val a:Int = 1

2.类型推断

类型推断:对于已声明赋值的变量,它允许省略类型定义。

3.range表达式

in A...B 关键字用来检查某个值是否在指定范围之内。

kotlin 复制代码
	if(age in 0..18){
        println("少年")
    }else if(age in 18..40){
        println("成年")
    }

4.when表达式

  • 允许你编写条件式,在某个条件满足时,执行对应代码
  • 只要包含else if分支,都建议改用when表达式
kotlin 复制代码
    val school = "小学"
    val level = when(school){
        "小学" -> 1
        "初中" -> 2
        "高中" -> 3
        else -> 0
    }
    println("level: " + level);

5.string模版

  • 模版支持在字符串的引号内放入变量值。
  • 还支持字符串里计算表达式的值并插入结果,添加在${}中的任何表达式,都会作为字符串的一部分求值。
kotlin 复制代码
    val school = "小学"
    println("$school")
    
    val flag = false
    println("Answer is : ${if(flag) "Yes" else "No"}")

6.函数

函数定义使用关键字 fun,参数格式为:参数 : 类型

kotlin 复制代码
fun add(a:Int , b:Int):Int{
    return a+b;
}

无返回值的函数

kotlin 复制代码
fun addNoReturn1(a:Int,b:Int,c:Int = 1){
    println("结果" + (a+b+c))
}

fun addNoReturn2(a:Int,b:Int,c:Int = 1) :Unit{
    println("结果" + (a+b+c))
}

可变长参数函数

kotlin 复制代码
fun addToSum(vararg nums:Int):Int{
    var sum = 0
    for(num in nums){
        sum += num
    }
    return sum
}

7.数据类型

Java中有两种数据类型:引用类型和基本数据类型。

Kotlin只提供引用类型这一种数据类型,出于更高性能的需要,Kotlin编译器会在Java中改用基本数据类型。

Kotlin 提供了多种内置数据类型,这些类型大致可以分为以下几类:
整数类型

  • Byte:8位有符号整数
  • Short:16位有符号整数
  • Int:32位有符号整数
  • Long:64位有符号整数

浮点类型:

  • Float:32位单精度浮点数
  • Double:64位双精度浮点数

字符类型

  • Char:表示一个单一的 16 位 Unicode 字符

布尔类型

  • Boolean:表示逻辑上的真(true)或假(false)

数组类型

  • 数组是一种用于存储固定大小的同类型元素的集合。例如,IntArray 用来存放整数数组,Array 用来存放字符串数组等。

字符串类型

  • String:不可变的字符序列

除了上述的基本类型外,Kotlin 还提供了一些特殊的类型如 Unit 和 Nothing:

  • Unit 类型类似于 Java 中的 void,它代表没有任何信息的值。如果一个函数没有返回任何有意义的结果,那么它的返回类型就是 Unit。
  • Nothing 类型则代表一个永远不会返回结果的函数。这种类型的函数通常用于抛出异常或者无限循环中。
    另外,Kotlin 不像 Java 那样区分原始类型和包装类型,所有的数值类型都是对象。但是,为了性能考虑,Kotlin 在后台会自动处理这些类型的特殊优化,使得它们的行为类似于 Java 的原始类型。

8.匿名函数

  • 定义时不取名字的函数,我们称之为匿名函数,匿名函数通常整体传递给其他函数,或者从其他函数返回。
kotlin 复制代码
fun main() {
    val total = "Mississippi".count()
    val count = "Mississippi".count { it == 's' }
    println(total)
    println(count)
}

9.函数参数

和具名函数一样,匿名函数可以不带参数,也可以带一个或者多个任何类型的参数,需要带参数时,参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中。

kotlin 复制代码
 val blessingFunction:(String) -> String = { name ->
        val holiday = "New Year"
        "Happy $holiday $name"
    }

    println(blessingFunction("Jack"))

10.it关键字

定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名。当你需要传入两个值参,it关键字就不能用了。

11.匿名函数的类型推断

定义一个变量时,如果已把匿名函数作为变量复制给它,就不需要显示指明变量类型。

kotlin 复制代码
    val blessingFunction = {
        val holiday = "New Year"
        "Happy $holiday"
    }

    println(blessingFunction())

类型推断也支持带参数的匿名函数,但为了帮助编译器更准确地推断变量的类型,匿名函数的参数名和参数类型必须有。

kotlin 复制代码
    val blessingFunction:(String,Int)-> String = { name:String,year:Int ->
        val holiday = "New Year"
        "$year $name Happy $holiday"
    }
    val blessingFunction = { name:String,year:Int ->
        val holiday = "New Year"
        "$year $name Happy $holiday"
    }

12.lambda

Lambda 表达式的完整语法形式如下:

kotlin 复制代码
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
  • lambda 表达式总是括在花括号中。
  • 完整语法形式的参数声明放在花括号内,并有可选的类型标注。
  • 函数体跟在一个 -> 之后。
  • 如果推断出的该 lambda 的返回类型不是 Unit,那么该 lambda 主体中的最后一个(或可能是单个)表达式会视为返回值。
kotlin 复制代码
val sum = { x: Int, y: Int -> x + y }

定义参数是函数的函数,如果一个函数的lambda参数排在最后,或者是唯一参数,那么括住lambda值参的一对圆括号可以省略

kotlin 复制代码
fun main() {

    val getDiscountWords = {goodsName : String,hour : Int ->
        val  currentYear = 2024
        if (hour > 12){
            "Discount for $goodsName in $currentYear $hour"
        }else{
            "No Discount for $goodsName in $currentYear $hour"
        }
    }

    showOnBoard("iPhone"){ goodsName,hour ->
        val  currentYear = 2024
        if (hour > 12){
            "Discount for $goodsName in $currentYear $hour"
        }else{
            "No Discount for $goodsName in $currentYear $hour"
        }
    }
}


fun showOnBoard(goodsName:String , getDiscountWords:(String,Int) -> String){
    val hour = (1..24).shuffled().last()
    println(getDiscountWords(goodsName,hour))
}

13.函数内联

内联(inline)函数是一种特殊的函数,它允许编译器将函数的调用处直接替换为函数体的代码。这种方式可以消除函数调用的开销,并且对于一些高阶函数(即接受其他函数作为参数或返回其他函数的函数)特别有用,因为它们通常会创建闭包对象来存储 lambda 表达式的上下文。

为什么使用内联?

  • 性能提升:通过消除函数调用的开销,尤其是当函数非常小的时候,内联可以提高程序的执行效率。
  • 非局部返回:内联函数中可以使用 return 直接从外部作用域返回,这在普通的函数中是不允许的。
  • 重载解析:内联函数可以在被调用时进行更精确的类型推断,从而影响到方法重载的选择。
  • 减少闭包对象的创建:当传递 lambda 表达式给函数时,如果没有内联,lambda 会被包装成一个对象。内联则可以直接将 lambda 的代码插入到调用处,避免了这种开销。

13.函数引用

函数引用是一种将函数本身作为值传递给其他代码的方式。这使得你可以像处理任何其他值一样处理函数,例如将它们存储在变量中、作为参数传递或从函数返回。Kotlin 提供了简洁的语法来创建函数引用,并且这些引用可以用于各种场景,比如与高阶函数一起使用。

函数引用的基本形式:创建一个函数引用,你只需要使用 :: 操作符加上函数名。

kotlin 复制代码
fun main() {

    showOnBoard("Laptop",::getDiscountWords)
}

private fun getDiscountWords(goodsName: String,hour:Int) : String {
    val  currentYear = 2024
    return if (hour > 12){
        "Discount for $goodsName in $currentYear $hour"
    }else{
        "No Discount for $goodsName in $currentYear $hour"
    }
}


private fun showOnBoard(goodsName:String , getDiscountWords:(String,Int) -> String){
    val hour = (1..24).shuffled().last()
    println(getDiscountWords(goodsName,hour))
}

14.高阶函数

函数类型也是有效的返回类型,也就是说可以定义一个能返回函数的函数。

kotlin 复制代码
fun main(){
    val getDiscountWords: (String) -> String = configDiscountWords()
    println(getDiscountWords("Apple"))
}

fun configDiscountWords() : (String) -> String {

    return { goodsName ->
        val  currentYear = 2024
        val hour = (1..24).shuffled().last()
        if (hour > 12){
            "Discount for $goodsName in $currentYear $hour"
        }else{
            "No Discount for $goodsName in $currentYear $hour"
        }
    }
}

15.闭包

在Kotlin中,匿名函数能修改并引用定义在自己作用域之外的变量,匿名函数引用着定义自身的函数里的变量,在Kotlin中的lambda就是闭包。

kotlin 复制代码
fun createCounter(): () -> Int {
    var count = 0  // 定义一个可变的局部变量
    return {
        count++  // lambda 捕获了 count 变量
    }
}

val counter = createCounter()
println(counter())  // 输出 1
println(counter())  // 输出 2

在这个例子中,createCounter 函数返回一个 lambda 表达式,该表达式每次调用时都会增加 count 的值。尽管 count 是在 createCounter 内部定义的局部变量,但返回的 lambda 仍然可以访问它,这就是闭包的作用。

注意事项:

  • 性能考虑:闭包可能会导致额外的内存开销,因为需要保持对捕获变量的引用。如果捕获的是大对象或大量数据,这可能会影响性能。
  • 变量捕获:在 Kotlin 中,lambda 表达式只能捕获那些在创建时就已经声明为 val 或 var 的变量。如果你尝试捕获一个没有初始化的变量,编译器会报错。
  • 不可变性:为了保证线程安全,通常建议只捕获不可变的数据。如果确实需要捕获可变状态,确保正确处理并发问题。
相关推荐
天若有情6731 分钟前
【Python】什么是列表推导式?
开发语言·python
xyd陈宇阳12 分钟前
C++ 入门三:函数与模板
开发语言·c++
星之卡比*12 分钟前
前端知识点---闭包(javascript)
开发语言·前端·javascript
fundroid18 分钟前
2025 跨平台技术如何选:KMP 与 Flutter 的核心差异
flutter·kotlin·kmp
鸿蒙布道师27 分钟前
鸿蒙NEXT开发设备相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
oioihoii33 分钟前
C++23新特性详解:迈向更现代化的C++
开发语言·c++·c++23
JoshuaGraham1 小时前
Java 并发-newFixedThreadPool
java·开发语言
darkchink1 小时前
[LevelDB]Block系统内幕解析-元数据块(Meta Block)&元数据索引块(MetaIndex Block)&索引块(Index Block)
android·java·服务器·c语言·数据库·c++·分布式
iFlyCai1 小时前
Xcode警报“Ignoring duplicate libraries: ‘-lc++’” 警报
开发语言·c++
Freak嵌入式1 小时前
一文速通 Python 并行计算:06 Python 多线程编程-基于队列进行通信
开发语言·python·多线程·面向对象·并行计算