中级:库与 API
为了最大限度地利用 Kotlin,请使用现有的库和 API,这样你就可以花更多时间编写代码,减少重复造轮子的时间。
库分发可复用代码,以简化常见任务。在库中,有用于对相关类、函数和实用工具进行分组的包和对象。库以一组函数、类或属性的形式公开 API(应用程序编程接口),供开发者在代码中使用。
让我们探索一下 Kotlin 的可能性。
标准库
Kotlin 有一个标准库,提供基本类型、函数、集合和实用工具,让你的代码简洁而富有表现力。标准库的很大一部分(kotlin
包中的所有内容)在任何 Kotlin 文件中都可随时使用,无需显式导入:
fun main() {
val text = "emosewa si niltoK"
// 使用标准库中的 reversed() 函数
val reversedText = text.reversed()
// 使用标准库中的 print() 函数
print(reversedText)
// Kotlin is awesome
}
然而,标准库的某些部分在使用前需要在代码中导入。例如,如果你想使用标准库的时间测量特性,你需要导入 kotlin.time
包。
在文件顶部,添加 import
关键字,后跟你需要导入的包:
import kotlin.time.*
星号 *
是一个通配符导入,它告诉 Kotlin 导入该包中的所有内容。你不能将星号 *
用于伴生对象。相反,你需要显式声明你想使用的伴生对象成员。
例如:
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
fun main() {
val thirtyMinutes: Duration = 30.minutes
val halfHour: Duration = 0.5.hours
println(thirtyMinutes == halfHour)
// true
}
此示例:
- 导入
Duration
类及其伴生对象的hours
和minutes
扩展属性。 - 使用
minutes
属性将30
转换为 30 分钟的Duration
。 - 使用
hours
属性将0.5
转换为 30 分钟的Duration
。 - 检测两个 Duration 是否相等并打印结果。
关于本示例中使用的函数和类的更详细探查,请参见 API 参考。
Kotlin 库
标准库涵盖了许多常见用例,但也有一些它无法解决的问题。幸运的是,Kotlin 团队和社区的其他成员开发了各种各样的库来补充标准库。例如,kotlinx-datetime
帮助你跨不同平台管理时间。
你可以在我们的 搜索平台 上找到有用的库。要使用它们,你需要采取额外步骤,例如添加依赖项或插件。每个库都有一个 GitHub 版本库,其中包含如何在你的 Kotlin 项目中包含它的说明。
一旦你添加了该库,你就可以导入其中的任何包。以下是导入 kotlinx-datetime
包以查找纽约当前时间的示例:
import kotlinx.datetime.*
fun main() {
val now = Clock.System.now() // Get current instant
println("Current instant: $now")
val zone = TimeZone.of("America/New_York")
val localDateTime = now.toLocalDateTime(zone)
println("Local date-time in NY: $localDateTime")
}
此示例:
- 导入
kotlinx.datetime
包。 - 使用
Clock.System.now()
函数创建Instant
类的实例,该实例包含当前时间,并将结果赋值给now
变量。 - 打印当前时间。
- 使用
TimeZone.of()
函数查找纽约的时区,并将结果赋值给zone
变量。 - 在包含当前时间的实例上调用
.toLocalDateTime()
函数,并将纽约时区作为实参。 - 将结果赋值给
localDateTime
变量。 - 打印根据纽约时区调整后的时间。
关于本示例中使用的函数和类的更详细探查,请参见 API 参考。
选择启用 API
库作者可能会将某些 API 标记为需要选择启用,然后你才能在代码中使用它们。他们通常在 API 仍在开发中且未来可能会改变时这样做。如果你不选择启用,你会看到如下警告或错误:
This declaration needs opt-in. Its usage should be marked with '@...' or '@OptIn(...)'
要选择启用,请编写 @OptIn
,后跟圆括号,其中包含对 API 进行分类的类名,再后跟两个冒号 ::
和 class
。
例如,标准库中的 uintArrayOf()
函数属于 @ExperimentalUnsignedTypes
,如 API 参考 中所示:
@ExperimentalUnsignedTypes
inline fun uintArrayOf(vararg elements: UInt): UIntArray
在你的代码中,选择启用看起来像这样:
@OptIn(ExperimentalUnsignedTypes::class)
下面是一个示例,它选择启用以使用 uintArrayOf()
函数创建无符号整数数组并修改其中一个元素:
@OptIn(ExperimentalUnsignedTypes::class)
fun main() {
// 创建一个无符号整数数组
val unsignedArray: UIntArray = uintArrayOf(1u, 2u, 3u, 4u, 5u)
// 修改一个元素
unsignedArray[2] = 42u
println("Updated array: ${unsignedArray.joinToString()}")
// Updated array: 1, 2, 42, 4, 5
}
此示例:
- 创建了一个无符号整数数组。
- 修改了其中一个元素。
这是最简单的选择启用方式,但还有其他方式。关于选择启用要求,请参见 选择启用要求。
练习
练习 1
你正在开发一个金融应用程序,帮助用户计算他们投资的未来价值。计算复利的公式是:
其中:
A
是计息后累计的金额(本金 + 利息)。P
是本金(初始投资)。r
是年利率(小数)。n
是每年复利的次数。t
是资金投资的年限(以年为单位)。
更新代码以:
- 从
kotlin.math
包 导入所需函数。 - 为
calculateCompoundInterest()
函数添加函数体,计算应用复利后的最终金额。
|--|--|
// Write your code here
fun calculateCompoundInterest(P: Double, r: Double, n: Int, t: Int): Double {
// Write your code here
}
fun main() {
val principal = 1000.0
val rate = 0.05
val timesCompounded = 4
val years = 5
val amount = calculateCompoundInterest(principal, rate, timesCompounded, years)
println("The accumulated amount is: $amount")
// The accumulated amount is: 1282.0372317085844
}
import kotlin.math.*
fun calculateCompoundInterest(P: Double, r: Double, n: Int, t: Int): Double {
return P * (1 + r / n).pow(n * t)
}
fun main() {
val principal = 1000.0
val rate = 0.05
val timesCompounded = 4
val years = 5
val amount = calculateCompoundInterest(principal, rate, timesCompounded, years)
println("The accumulated amount is: $amount")
// The accumulated amount is: 1282.0372317085844
}
练习 2
你希望测量程序中执行多个数据处理任务所需的时间。更新代码,从 kotlin.time
包中添加正确的导入语句和函数:
// Write your code here
fun main() {
val timeTaken = /* Write your code here */ {
// Simulate some data processing
val data = List(1000) { it * 2 }
val filteredData = data.filter { it % 3 == 0 }
// Simulate processing the filtered data
val processedData = filteredData.map { it / 2 }
println("Processed data")
}
println("Time taken: $timeTaken") // e.g. 16 ms
}
示例解决方案
import kotlin.time.measureTime
fun main() {
val timeTaken = measureTime {
// Simulate some data processing
val data = List(1000) { it * 2 }
val filteredData = data.filter { it % 3 == 0 }
// Simulate processing the filtered data
val processedData = filteredData.map { it / 2 }
println("Processed data")
}
println("Time taken: $timeTaken") // e.g. 16 ms
}
练习 3
最新 Kotlin 版本中有一个新的标准库特性。你想尝试使用它,但它需要选择启用。该特性属于 @ExperimentalStdlibApi
。在你的代码中,选择启用应该是什么样子?
@OptIn(ExperimentalStdlibApi::class)