介绍
Kotlite 是一个开源的类型安全编程语言,它拥有 Kotlin 编程语言 脚本 变体的丰富子集。它附带了标准库,这些库是 Kotlin Multiplatform/Common 标准库和一些第三方库的子集。
Kotlite 解释器 是一个轻量级的 Kotlin Multiplatform 库,用于解释和执行用 Kotlite 编写的代码,并在主机运行时环境和嵌入式运行时环境之间建立桥梁。
Kotlite 解释器的主要特性
-
支持 Kotlin 1.9 语言和标准库的一个子集。https://kotlinlang.org/[Kotlin] 是一个出色、安全、描述性强且灵活的语言。请查看 Kotlite 与 Kotlin 之间的区别。
-
支持编写复杂的泛型代码
-
可嵌入 — 它是一个库
-
安全
-
可以白名单或黑名单库或内置中的类
-
可以白名单或黑名单库或内置中的扩展函数
-
可以白名单或黑名单库或内置中的扩展属性
-
可以白名单或黑名单库或内置中的全局属性
-
标准库中没有文件或网络 I/O 或操作系统 API
-
-
多平台运行
-
可扩展并允许与主机交互
-
允许从主机提供自定义扩展函数
-
允许从主机提供自定义扩展属性
-
允许从主机提供自定义全局属性
-
允许实现自定义库并将调用委托给一等 Kotlin 函数和属性
-
允许从主机读取嵌入式环境中全局变量的值
-
嵌入式环境的标准输出管道是可覆盖的
-
-
轻量级 —
kotlinc超过 300 MB,而 Kotlite 加上所有平台标准库的总和小于 10 MB。Web 演示的 JS 脚本小于 800 KB。 -
执行前进行语义分析,例如变量访问和类型验证
-
类型推断
-
经过良好测试 — 每个平台有超过一千个手工编写的单元测试
-
可以在任何支持 Kotlin 1.9 的 IDE 中编写 — Kotlite 不会创建新语法
| 说实话,标准库没有经过良好测试。只有语言本身经过了良好测试。如果发现任何问题,请帮忙报告。 |
支持的平台
-
JVM (Java, Kotlin/JVM, …)
-
JS
-
Android (JVM)
-
iOS
-
macOS
-
watchOS
-
tvOS
除了内置组件外,解释器不依赖任何特定平台的 API,因此对于有经验的开发者来说,将这个库移植到 Kotlin Multiplatform 支持的任何其他平台应该很容易。
使用场景
Kotlite 是为以下使用场景设计的。
-
以安全方式执行用户提供的简单表达式
-
以安全方式执行用户提供的脚本
-
允许用 Kotlin 代码编写的自定义插件,以安全方式用于任何 Kotlin 或 JVM 应用程序
-
安全地执行来自服务器的代码
-
随时更新移动应用 UI,而无需向应用商店提交应用更新(这需要社区贡献)
非目标
-
Kotlite 不会取代 Kotlin
-
Kotlite 不会引入 Kotlin 中未提供的新编程语言特性或语法,除了支持 Kotlite 内部工具所需的内容
副产品
-
使用 mermaid 将 Kotlite 代码渲染为 AST(抽象语法树)图表
-
Kotlite 代码的静态分析
-
从 Kotlite 代码生成 AST 节点
-
重新格式化 Kotlite 代码
演示
Kotlite 与 Kotlin 语法对比
概述
Kotlite 是 Kotlin 语言的一个轻量级子集,专注于嵌入式脚本执行。本文档将详细比较 Kotlite 和标准 Kotlin 之间的语法差异,帮助你快速理解两者之间的关系。
核心语言特性对比
变量声明
Kotlin:
val immutableVar = "Hello"
var mutableVar = 42
Kotlite:
val immutableVar = "Hello"
var mutableVar = 42
状态: ✅ 完全支持
数据类型
Kotlin:
val int: Int = 42
val long: Long = 100L
val double: Double = 3.14
val string: String = "Hello"
val boolean: Boolean = true
val char: Char = 'A'
Kotlite:
val int: Int = 42
val long: Long = 100L
val double: Double = 3.14
val string: String = "Hello"
val boolean: Boolean = true
val char: Char = 'A'
状态: ✅ 基本类型完全支持
函数声明
Kotlin:
fun greet(name: String): String {
return "Hello, $name!"
}
fun add(a: Int, b: Int): Int = a + b
Kotlite:
fun greet(name: String): String {
return "Hello, $name!"
}
fun add(a: Int, b: Int): Int = a + b
状态: ✅ 完全支持
Lambda 表达式
Kotlin:
val sum: (Int, Int) -> Int = { a, b -> a + b }
val numbers = listOf(1, 2, 3)
val doubled = numbers.map { it * 2 }
Kotlite:
val sum: (Int, Int) -> Int = { a, b -> a + b }
val numbers = listOf(1, 2, 3)
val doubled = numbers.map { it * 2 }
状态: ✅ 支持
不支持或有限支持的特性
类和对象
Kotlin:
class Person(val name: String, var age: Int) {
fun greet() {
println("Hello, my name is $name")
}
}
object Singleton {
const val CONSTANT = 42
}
Kotlite:
// 类声明支持有限
// 主要用于内置类型和标准库
状态: ⚠️ 有限支持 - 主要用于内置类型,自定义类支持有限
泛型
Kotlin:
fun <T> printList(list: List<T>) {
list.forEach { println(it) }
}
class Box<T>(val item: T)
Kotlite:
// 泛型在标准库中可用
val list: List<String> = listOf("a", "b", "c")
val map: Map<String, Int> = mapOf("one" to 1, "two" to 2)
状态: ⚠️ 标准库泛型可用,自定义泛型有限
扩展函数
Kotlin:
fun String.repeat(count: Int): String {
return this.repeat(count)
}
Kotlite:
// 扩展函数在标准库中可用
"Hello".uppercase()
listOf(1, 2, 3).map { it * 2 }
状态: ⚠️ 标准库扩展函数可用,自定义扩展可通过主机环境注册
协程
Kotlin:
suspend fun fetchData(): String {
delay(1000)
return "Data"
}
fun main() {
runBlocking {
println(fetchData())
}
}
Kotlite:
// 不支持协程
状态: ❌ 不支持
控制流对比
if/else
Kotlin:
val max = if (a > b) a else b
Kotlite:
val max = if (a > b) a else b
状态: ✅ 完全支持
when 表达式
Kotlin:
val result = when (x) {
0 -> "Zero"
1 -> "One"
else -> "Other"
}
Kotlite:
val result = when (x) {
0 -> "Zero"
1 -> "One"
else -> "Other"
}
状态: ✅ 完全支持
循环
Kotlin:
for (i in 0 until 10) { println(i) }
for (item in list) { println(item) }
while (condition) { /* ... */ }
do { /* ... */ } while (condition)
Kotlite:
for (i in 0 until 10) { println(i) }
for (item in list) { println(item) }
while (condition) { /* ... */ }
do { /* ... */ } while (condition)
状态: ✅ 完全支持
标准库支持
核心库
功能 |
Kotlin |
Kotlite |
字符串操作 |
✅ 完整 |
✅ 主要功能 |
集合操作 |
✅ 完整 |
✅ 主要功能 |
数学运算 |
✅ 完整 |
✅ 主要功能 |
IO 操作 |
✅ 完整 |
⚠️ 有限(安全优先) |
常用集合
Kotlin:
val list = mutableListOf(1, 2, 3)
val map = mutableMapOf("a" to 1, "b" to 2)
val set = mutableSetOf(1, 2, 3)
Kotlite:
val list = mutableListOf(1, 2, 3)
val map = mutableMapOf("a" to 1, "b" to 2)
val set = mutableSetOf(1, 2, 3)
状态: ✅ 主要集合类型完全支持
安全性特性
空值安全
Kotlin:
val nullable: String? = null
val length = nullable?.length ?: 0
Kotlite:
val nullable: String? = null
val length = nullable?.length ?: 0
状态: ✅ 完全支持
异常处理
Kotlin:
try {
// 可能抛出异常的代码
} catch (e: Exception) {
// 处理异常
} finally {
// 清理代码
}
Kotlite:
try {
// 可能抛出异常的代码
} catch (e: Exception) {
// 处理异常
} finally {
// 清理代码
}
状态: ✅ 完全支持
实际使用建议
使用 Kotlite 的最佳场景
-
用户脚本执行 - 安全地执行用户提供的脚本
-
配置语言 - 使用 Kotlin 语法作为配置文件
-
嵌入式表达式 - 在应用中嵌入简单表达式
-
插件系统 - 安全的插件扩展机制
迁移指南
从 Kotlin 迁移到 Kotlite:
-
移除类和对象声明
-
避免使用协程
-
简化复杂的泛型使用
-
使用提供的标准库函数
-
利用主机环境注册自定义函数
性能考虑
Kotlite 的优势: - 启动时间快 - 内存占用小 - 安全的执行环境 - 跨平台支持
限制: - 不支持 JIT 编译 - 复杂计算可能较慢 - 某些高级特性不可用
总结
Kotlite 是 Kotlin 的一个精心设计的子集,专注于安全的嵌入式脚本执行。虽然它不支持 Kotlin 的所有特性,但它提供了足够的功能来处理大多数脚本场景,同时保持了 Kotlin 优雅的语法和类型安全。
选择 Kotlite 当你需要: - 安全执行用户脚本 - 轻量级嵌入式解释器 - 跨平台兼容性 - Kotlin 语法的熟悉感
选择完整 Kotlin 当你需要: - 完整的语言特性 - JVM/JS/Native 编译 - 协程和异步编程 - 复杂的 OOP 设计
功能请求或问题报告
非常高兴您可以通过提出功能请求或报告问题来为此项目做出贡献。
如果之前尚未有人提出,请在 GitHub 仓库 中提出工单。否则,请为该工单投票。
对于问题报告,请包括以下内容:
-
能够复现问题的最小代码
-
平台语言、操作系统和版本(例如 Windows 上的 JVM 21)
-
预期结果
-
实际结果
报告的问题将根据重要性、完整性和可用性进行优先级排序并尽快解决。
如果您有任何使用问题,请访问 GitHub 仓库的讨论区 并搜索是否有人之前问过同样的问题。如果没有,请随时创建新的讨论。
Kotlite 解释器
入门指南
包含依赖项
首先,包含依赖项。
Kotlite 解释器
Kotlite 标准库
对于单平台:
dependencies {
implementation("io.github.sunny-chung:kotlite-interpreter:<version>")
implementation("io.github.sunny-chung:kotlite-stdlib:<version>")
// ...
}
对于多平台:
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api("io.github.sunny-chung:kotlite-interpreter:<version>")
api("io.github.sunny-chung:kotlite-stdlib:<version>")
// ...
}
}
// ...
阶段
开发者应该熟悉大部分阶段。
在语义分析阶段,它会做很多事情,比如检查类中的函数是否试图覆盖不存在的函数、返回错误数据类型的值、类型推断、代码优化等等。
任何阶段都可能抛出异常。
不同块中的阶段不需要在前一个阶段之后立即调用。
最小示例
了解了这些阶段后,我们可以开始编写代码了。
打印 Hello world!
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
val interpreter = KotliteInterpreter(
filename = "Hello",
code = """
println("Hello world!")
""".trimIndent(),
executionEnvironment = env,
)
interpreter.eval()
解析和语义分析在 KotliteInterpreter() 函数中执行。可以将其想象为一个"编译过程"。如果有任何错误,在 eval() 调用之前,会从这个函数抛出异常。
|
filename 参数仅用于错误消息和堆栈跟踪。
|
获取执行结果的全局值
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
val interpreter = KotliteInterpreter(
filename = "Calculate",
code = """
val a = (1..10).fold(0) { acc, it ->
acc + it
}
""".trimIndent(),
executionEnvironment = env,
)
interpreter.eval()
val symbolTable = interpreter.symbolTable()
val a = (symbolTable.findPropertyByDeclaredName("a") as IntValue).value // 55
仅计算一个表达式
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
val result: IntValue = evalKotliteExpression(
filename = "Calculate",
code = "(1..10).fold(0) { acc, it -> acc + it }",
executionEnvironment = env,
) as IntValue
val a: Int = result.value // 55
值和类型类
evalKotliteExpression() 或 SymbolTable.findPropertyByDeclaredName() 或 Interpreter.eval() 返回的所有值,或提供给自定义函数/属性的值参数,都是 RuntimeValue 的子类型。RuntimeValue 的可能子类型有:
-
IntValue -
LongValue -
DoubleValue -
CharValue -
StringValue -
BooleanValue -
ByteValue -
NullValue -
UnitValue -
LambdaValue -
ThrowableValue -
ClassInstance
RuntimeValue 有一个成员函数 type(),它返回底层值的类型。返回类型是 DataType 的子类型。当有类型参数提供给自定义函数/属性时,也会提供 DataType。
供消费者使用的 DataType 的可能子类型有:
-
ObjectType -
FunctionType -
UnitType -
NothingType -
TypeParameterType -
StarType -
RepeatedType
在大多数情况下,会返回 ObjectType。可以在 ObjectType 类中访问底层类定义、泛型类型参数和可空性。
DataType 有一个字符串成员属性 descriptiveName,它返回一个可读的类型名称,例如,"MutableMap<MyPair<Int, Boolean>, List<String?>>?"。
线程安全
解释器本身*不是*线程安全的。Kotlite 解释器执行的代码不能在多个线程上运行。
然而,Kotlite 解释器不保存全局状态。因此,可以运行不同的解释器实例并在多个线程中并发执行是可能的。
如果在提供的自定义函数中强制执行互斥锁,它也可能工作。
可重用性
大多数 Kotlite 类不能重用,包括 ExecutionEnvironment、AST 节点、解析器和解释器。它们包含状态。如果想要重复执行或使用相同的 ExecutionEnvironment 输入,必须重复调用。
安全
标准库委托
标准库是通过委托给主机环境中的原始 Kotlin / 第三方 API 和类来实现的。例如,库函数 fun String.toRegex(): Regex 的实现会将 StringValue 转换为主机环境中的真实 String,然后调用 toRegex(),并以包装形式将 Regex 实例返回给嵌入式环境。这种委托方法可能会带来安全隐患。
虽然大多数 Kotlite 内置标准库执行起来应该是安全的,但委托给某些第三方库可能是不想要的。
过滤类、函数和属性
因此,Kotlite 提供了一种从嵌入式执行环境中移除它们的方法。
这可以通过向 ExecutionEnvironment 提供过滤函数来完成。
内置的东西,例如 Int,也可以被过滤掉,但这可能会在代码执行和导入库期间造成问题,并且没有安全收益。
下面是一个在不破坏环境的情况下完全移除类 MutableList 的示例。
val env = ExecutionEnvironment(
classRegistrationFilter = {
it != "MutableList"
},
functionRegistrationFilter = {
!(it.receiverType ?: "").contains("MutableList") &&
!it.returnType.contains("MutableList")
},
).apply {
install(AllStdLibModules())
}
assertFailsWith<SemanticException> {
KotliteInterpreter(
filename = "<Test>",
code = """
val a = mutableListOf(1, 2, 3)
""".trimIndent(),
executionEnvironment = env
)
}
| 开发者仍然可以创建一个具有相同名称的类,就像该类从未存在过一样。这不会造成危害,因为它不会与主机交互。 |
选择性地安装库
可以只将特定的库安装到 ExecutionEnvironment 中。
val env = ExecutionEnvironment().apply {
install(TextLibModule())
install(CollectionsLibModule())
install(ByteLibModule())
}
顺序很重要。如果一个库模块依赖另一个模块,被依赖的模块应该先安装。
equals()、hashCode()、toString()、compareTo() 中的隐式代码执行
正如前面提到的,标准库只是对真实 API 和类的委托。
为了支持对自定义类的列表进行排序或使用自定义类作为 Map 的键的用例,最终用户可以在 Kotlite 中覆盖 equals()、hashCode()、toString()、compareTo() 函数。在主机环境中,调用这些函数将执行用户覆盖的代码,并可能抛出异常。这可能是不想要的代码执行和风险。
请记住,在您的应用程序中执行 a == b 或 "Debug: $a" 可能会执行用户代码。
资源使用
目前没有办法限制用户代码执行的内存使用或计算资源。用户代码可以通过无限循环耗尽所有可用内存或减慢操作系统。这一领域可能会在未来得到改善。
与主机集成
有一些 API 允许主机向嵌入式脚本环境提供自定义可执行函数和属性。这些 API 尚未稳定,将来可能会发生变化。
| 创建集成类似于创建库模块。建议阅读 创建库模块 中的详细信息,以深入了解此主题。 |
提供函数和扩展函数
要提供一个扩展函数,请使用 ExecutionEnvironment.registerFunction(CustomFunctionDefinition) API。
下面的示例提供了一个签名为 fun String.size(factor: Int): Int 的扩展函数。该函数还在返回之前更改主机环境中的变量 hostVar。
var hostVar: Int = 0
val env = ExecutionEnvironment().apply {
registerFunction(CustomFunctionDefinition(
receiverType = "String",
functionName = "size",
returnType = "Int",
parameterTypes = listOf(CustomFunctionParameter("factor", "Int")),
executable = { interpreter, receiver, args, typeArgs ->
IntValue((receiver as StringValue).value.length * (args[0] as IntValue).value, interpreter.symbolTable()).also {
hostVar = it.value
}
},
position = SourcePosition("MyBridge", 1, 1),
))
}
position 的值仅在有错误或运行时异常时使用,以尝试提供有关错误的更多信息。
|
要提供一个全局函数,只需为 receiverType 参数提供 null 值。
提供扩展属性
要提供一个扩展属性,请使用 ExecutionEnvironment.registerExtensionProperty(ExtensionProperty) API。
下面是一个将主机变量暴露给脚本环境以读取和写入值的示例。
var hostScopeVariable = 0
val env = ExecutionEnvironment().apply {
registerExtensionProperty(ExtensionProperty(
declaredName = "f",
receiver = "String",
type = "Int",
getter = { interpreter, subject, typeArgs ->
IntValue(hostScopeVariable, interpreter.symbolTable())
},
setter = { interpreter, subject, value, typeArgs ->
hostScopeVariable += (value as IntValue).value
}
))
}
val interpreter = KotliteInterpreter(
filename = "MyScript",
code = """
val s = "abcde"
s.f = 10
val a = s.f // 10
s.f = 15
val b = s.f // 25
""".trimIndent(),
executionEnvironment = env,
)
interpreter.eval()
如果没有 getter 或 setter,getter 或 setter 参数可以是 null。
|
提供全局属性
提供全局属性的 API 与提供扩展属性的 API 不同。它是 ExecutionEnvironment.registerGlobalProperty(GlobalProperty)。
var property = 10
val env = ExecutionEnvironment().apply {
registerGlobalProperty(GlobalProperty(
position = SourcePosition("MyScript", 1, 1),
declaredName = "x",
type = "Int",
isMutable = true,
getter = { interpreter -> IntValue(property, interpreter.symbolTable()) },
setter = { interpreter, value -> property = (value as IntValue).value },
))
registerGlobalProperty(GlobalProperty(
position = SourcePosition("Math", 1, 1),
declaredName = "myPi",
type = "Double",
isMutable = false,
getter = { interpreter -> DoubleValue(3.14, interpreter.symbolTable()) },
))
}
正如示例中所示,getter 或 setter 可以是可选的(null)。
|
在可执行文件中执行其他函数
API 不太友好,但这是可能的。
执行 lambda 参数
核心标准库有一些好的示例。
CustomFunctionDefinition(
receiverType = "T",
functionName = "also",
returnType = "T",
typeParameters = listOf(TypeParameter(name = "T", typeUpperBound = null)),
parameterTypes = listOf(CustomFunctionParameter("block", "(T) -> Unit")),
executable = { interpreter, receiver, args, typeArgs ->
val block = args[0] as LambdaValue
block.execute(arrayOf(receiver))
receiver!!
},
position = SourcePosition(name, 1, 1),
),
CustomFunctionDefinition(
receiverType = "T",
functionName = "apply",
returnType = "T",
typeParameters = listOf(TypeParameter(name = "T", typeUpperBound = null)),
parameterTypes = listOf(CustomFunctionParameter("block", "T.() -> Unit")),
executable = { interpreter, receiver, args, typeArgs ->
val block = args[0] as LambdaValue
block.execute(arguments = emptyArray(), receiver = receiver!!)
receiver!!
},
position = SourcePosition(name, 1, 1),
),
| 顺序很重要。如果 A 依赖于 B,则将 B 放在 A 之前。 |
执行其他已声明的函数
这并不容易,也不是常见的用例。请查看 /interpreter/src/commonMain/kotlin/com/sunnychung/lib/multiplatform/kotlite/model/SpecialFunction.kt 中的示例。
创建库模块
库模块只是自定义类、函数、扩展函数、扩展属性和全局属性的集合。
| 顺序很重要。如果 A 依赖于 B,则将 B 放在 A 之前。 |
Kotlite 解释器 API
让我们从提供自定义函数开始。通常过程是这样的:
在 CustomFunctionDefinition 中,executable lambda 参数如下所示:
{ interpreter: Interpreter, receiver: RuntimeValue?, args: List<RuntimeValue>, typeArgs: Map<String, DataType> ->
// ...
}
| 对于自定义属性,API 和过程是相似的。本节也适用于它们。 |
RuntimeValue — 包装 Kotlin 值的 Kotlite 值
在代码级别,Kotlin 主机中的 Kotlite 值是一个 RuntimeValue。将 Kotlin 值包装为 RuntimeValue 需要技巧。下面列出了如何包装它们。
| Kotlin 类型 | 转换为 Kotlite 值的代码 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
非泛型对象 |
其中 |
泛型对象 |
其中 |
标准库支持的对象 |
非详尽列表:
示例:
|
对于像 List、Map 或 Pair 这样的嵌套类,别忘了包装所有嵌套值。否则,事情会出错,并且在代码执行期间可能会抛出异常。
|
SymbolTable
可以通过 Interpreter.symbolTable() 获取 SymbolTable。SymbolTable 不能被持久化,因为它在另一个函数调用的上下文中可能不同,并且持久化它会导致内存泄漏。
ClassDefinition 和 ProvidedClassDefinition
对于标准库中可用的类型,通常可以通过 ${TypeName}Class.clazz 找到。例如,MutableListClass.clazz 用于类 MutableList。
对于 Kotlite 未知的类型,您将必须提供一个自定义的 ClassDefinition。
ProvidedClassDefinition 是一个为库用户定义类的友好 API。它扩展了 ClassDefinition。可以在 这里 找到一个示例。
DataType
如果需要创建泛型 Kotlite 值,例如,一个 List<T> 值,需要一个或多个 DataType 来指定类型参数。可以从多种方式获取它。
-
如果它在函数调用的类型参数中可用,请使用
typeArgs[name]。
例如,对于像这样的函数签名:
fun <T, R : Comparable<R>> MutableList<T>.sortBy(selector: (T) -> R?)
typeArgs["T"] 是 DataType 中的 T 类型参数,typeArgs["R"] 是 DataType 中的 R 类型参数。
-
基本数据类型
可以从 SymbolTable 获取。例如,symbolTable.IntType。对于一些特殊类型,如 Any、Unit 和 Nothing,可以直接构造:UnitType(isNullable: Boolean = false)。
-
对于其他类型,可以通过便捷扩展函数
String.toDataType(symbolTable: SymbolTable)获取。例如,
val symbolTable: SymbolTable = interpreter.symbolTable()
val byteArrayType: DataType = "ByteArray".toDataType(symbolTable)
val pairType: DataType = "Pair<String, Pair<Double, Int>>".toDataType(symbolTable)
val genericType: DataType = "Map<K, Int>".toDataType(symbolTable)
| 如果有不受信任的用户输入,此方法容易受到 注入攻击。 |
将 Kotlite RuntimeValue 解包为 Kotlin 值
这相对简单。只需转换为正确的类型并调用成员属性 .value。
| Kotlin 类型 | 将 Kotlite 值转换为 Kotlin 值的代码 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Object |
|
对于像 List、Map 或 Pair 这样的嵌套类,必要时别忘了解包所有嵌套值。
|
手动方法
创建一个扩展抽象类 LibraryModule 的类,给它命名,包含所有实现,然后这个类就是一个可以安装的库模块。
采用这种方法具有最佳性能,但需要编写大量重复代码。
标准库中的 IOLibModule 是一个值得参考的好示例,因为它是一个完全手工编写的库模块。
IOLibModule
Unresolved directive in Creating Library Modules.adoc - include::../../stdlib/src/commonMain/kotlin/com/sunnychung/lib/multiplatform/kotlite/stdlib/IOLibModule.kt[]
委托方法
这种方法是大多数 Kotlite 标准库采用的方法。将所有内容委托给 Kotlin,并使用 Kotlite 标准库处理器 Gradle 插件生成所有委托代码。
在委托调用执行期间,Kotlite 会在需要时将 Kotlite RuntimeValue 解包为 Kotlin 类型,执行委托函数,然后将结果包装为 Kotlite RuntimeValue。当主体、参数或结果是具有大尺寸的 Collection 时,时间性能损失会很显著。
下面是一个生成委托库模块的最小示例。示例中采用了 Regex 和 Collection 库模块中的一些内容。
pluginManagement {
repositories {
mavenCentral()
// ...
}
}
Kotlite 库预处理器 Gradle 插件
plugins {
kotlin("multiplatform")
id("io.github.sunny-chung.kotlite-stdlib-processor-plugin") version "<version>"
}
// ...
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
// ...
}
kotlin.srcDir(tasks.named("kotliteStdlibHeaderProcess").map { it.outputs })
}
// ...
kotliteStdLibHeaderProcessor {
inputDir = "src/kotlinheader/"
outputDir = "build/generated/common/"
outputPackage = "com.sunnychung.lib.multiplatform.kotlite.stdlib"
configs = mapOf(
"Regex" to KotliteModuleConfig(
imports = listOf(
"com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexClass",
"com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexValue",
)
),
)
}
实现委托类和值工厂函数。
fun RegexValue(value: Regex, symbolTable: SymbolTable) : DelegatedValue<Regex>
= DelegatedValue<Regex>(value, "Regex", RegexClass.clazz, symbolTable = symbolTable)
object RegexClass {
val clazz = ProvidedClassDefinition(
fullQualifiedName = "Regex",
typeParameters = emptyList(),
isInstanceCreationAllowed = true,
primaryConstructorParameters = listOf(CustomFunctionParameter("value", "String")),
constructInstance = { interpreter, callArguments, callPosition ->
RegexValue(Regex((callArguments[0] as StringValue).value), interpreter.symbolTable())
},
position = SourcePosition("Regex", 1, 1),
)
}
工厂函数名称必须是 ${ActualTypeName}Value。它适用于任何类型,无论原语或接口。此约定在代码生成插件中是硬编码的。
|
通过编写所有要委托的全局或扩展函数和扩展属性来创建一个 Kotlin 头文件,但不写主体。此文件应放在 /your-library/src/kotlinheader/${LibraryName}.kt 中。
fun String.matches(regex: Regex): Boolean
fun String.replace(regex: Regex, replacement: String): String
fun String.replaceFirst(regex: Regex, replacement: String): String
fun String.toRegex(): Regex
val <T> List<T>.size: Int
get()
val <T> List<T>.lastIndex: Int
get()
编译时,将生成一个抽象类 Abstract${name}LibModule。检查生成的代码是否可编译且正确。可以通过编写单元测试来检查。
生成代码的示例
Unresolved directive in Creating Library Modules.adoc - include::../../stdlib/build/generated/common/AbstractRegexLibModule.kt[]
| 代码生成插件有很多硬编码。您可能想要分支另一个并添加更多硬编码内容。 |
最后,创建一个类 ${name}LibModule 扩展这个抽象类,必要时覆盖或添加任何内容,然后就完成了。
Unresolved directive in Creating Library Modules.adoc - include::../../stdlib/src/commonMain/kotlin/com/sunnychung/lib/multiplatform/kotlite/stdlib/RegexLibModule.kt[]
空值
在正常情况下,Kotlite 的 null 值在传递给委托调用之前会映射为 NullValue。如果委托函数需要真实的 null 值才能正常工作,例如 setOfNotNull() 或 filterNotNull,则被视为空值感知。
在这种情况下,在 Kotlin 头文件中为这些函数添加 nullaware 修饰符,然后生成的代码会将 NullValue 映射为 null。例如:
nullaware fun <T : Any> Iterable<T?>.filterNotNull(): List<T>
nullaware fun <T : Any> setOfNotNull(vararg elements: T?): Set<T>
委托给 Kotlin 值的 equals()、hashCode()、toString()
出于安全原因,它们默认不会被委托。需要显式的委托声明。
对于手动方法,下面是一个委托 CustomClass.toString() 的示例。
val env = ExecutionEnvironment().apply {
registerClass(CustomClass.clazz)
registerFunction(CustomFunctionDefinition(
position = SourcePosition.NONE,
receiverType = "CustomClass",
functionName = "toString",
returnType = "String",
parameterTypes = emptyList(),
executable = { interpreter, receiver, args, typeArgs ->
StringValue((receiver as DelegatedValue<*>).value.toString(), interpreter.symbolTable())
}
))
}
对于委托方法,在 Kotlin 头文件中声明。下面是一个委托 KInstant.toString() 的示例。
fun KInstant.toString(): String
分发
Kotlite 不提供分发或托管库的方法。将源代码放在 GitHub 上并创建一个 awesome-kotlite 仓库可能是一个选择。
生成 AST 图表
可以从 Kotlite 代码生成 mermaid 代码来渲染 AST 图表。
下面是一个示例。
val mermaidCode = kotliteAstNodeMermaidDiagram("""
val cache = mutableMapOf<Int, Long>()
fun fib(i: Int): Long {
if (i < 0) throw Exception("Invalid i: ${'$'}i")
if (i <= 1) return i.toLong()
if (i in cache) {
return cache[i]!!
}
return (fib(i - 2) + fib(i - 1)).also {
cache[i] = it
}
}
val a = fib(19) // 4181L
""".trimIndent())
println(mermaidCode, MermaidFlowchartDirection.LeftToRight)
对于上述代码片段,传递给 mermaid 后,生成的图表如下所示。
高级用法
工具结构
Kotlite 中有几个关键工具。执行方向在此图表中大致呈现。
| 代码生成器生成带有可选调试信息的 Kotlin 代码。主要用于调试目的。 |
数据流如下:
所有工具类都标记为 open。开发人员可以自由扩展这些工具来创建新功能。
AST 节点
解析器生成抽象语法树 (AST) 节点。解析器的函数与 Kotlin 语法 中定义的每个语法相对应。函数名称即为语法名称。
例如,调用 Parser.script() 根据 Kotlin 语法中的 script 定义解析代码,而 Parser.type() 根据 type 语法解析代码。
下面的 Kotlin 代码将字符串中编写的类型解析为语义分析器和其他工具可以使用的 AST 节点。
val simpleTypeNode: ASTNode = Parser(Lexer("(anything)", "Double")).type()
val complexTypeNode: ASTNode = Parser(Lexer("(anything)", "Map<String, MutableList<Pair<Int, Double>>>")).type()
val genericTypeNode: ASTNode = Parser(Lexer("(anything)", "Map<K, V>")).type()
val functionTypeNode: ASTNode = Parser(Lexer("(anything)", "Int.(T) -> Unit")).type()
下面的 Kotlin 代码将字符串中编写的表达式解析为语义分析器和其他工具可以使用的 AST 节点。
val expressionNode: ASTNode = Parser(Lexer("(anything)", "(1 + 2 * 3) / 4")).expression()
将其传递给语义分析器和解释器并手动执行。
val executionEnvironment = ExecutionEnvironment()
SemanticAnalyzer(
rootNode = expressionNode,
executionEnvironment = executionEnvironment,
).analyze()
val result = Interpreter(
rootNode = expressionNode,
executionEnvironment = executionEnvironment,
).eval() as IntValue
val intResult: Int = result.value // 1
标准库
目前,标准库包含以下 Kotlin/Common 标准库模块:
-
kotlin
-
kotlin.collections
-
kotlin.io
-
kotlin.math
-
kotlin.ranges
-
kotlin.text
以及以下外部库:
目前,它们的所有函数和属性并未全部导入,但只要包含它们不会带来安全问题,计划支持所有这些内容。
标准库也将继续扩展。正则匹配器、编码、哈希和加密库在短期目标列表上。
但由于潜在的安全问题,标准库中将不提供文件 I/O 和网络功能。需要它们的用户可以实现一个 委托库模块。
重定向标准输出管道
可以将嵌入式脚本环境的标准输出流重定向到其他地方,例如 StringBuilder。
如果手动安装 IOLibModule,可以重写其成员函数 outputToConsole。
val console = StringBuilder()
val env = ExecutionEnvironment().apply {
install(object : IOLibModule() {
override fun outputToConsole(output: String) {
console.append(output)
}
})
}
如果改为安装 AllStdLibModules,它接受一个可选的构造函数 lambda 参数 outputToConsoleFunction。
val console = StringBuilder()
val env = ExecutionEnvironment().apply {
install(AllStdLibModules(outputToConsoleFunction = {
console.append(it)
}))
}
已知问题或限制
有一些已知问题可能不会在短期内解决。它们可能会在之后的时间得到解决,并且在完全解决之前可能会逐步改进。
-
在默认 JVM 参数的 JVM 中,递归调用的深度只支持约 140 层。超过这个限制,会抛出 "StackOverflowError"。
-
深度递归调用使用大量内存且运行速度较慢
Kotlite 语言
语言
Kotlite 解析器实现主要符合 官方 Kotlin 1.9 文档。因此,支持的语法和优先级解析应该与 Kotlin 1.9 等效。
与 Kotlin 的区别
| Kotlin 1.9 | Kotlite Script | Kotlite API |
|---|---|---|
基本数据类型 |
||
Byte |
✓ |
|
Short |
✕ |
|
Int |
✓ |
|
Long |
✓ |
|
Float |
✕ |
|
Double |
✓ |
|
无符号数字 |
✕ |
|
Boolean |
✓ |
|
Char |
✓ |
|
String |
✓ |
|
Array |
除了 ByteArray 外不支持。List 是替代品。 |
|
Pair |
✓ |
|
Triple |
✕ |
|
Throwable |
✓ |
|
Unit |
✓ |
|
字面常量 |
||
十进制 |
✓ |
|
Long - |
✓ |
|
十六进制 - |
✕ |
|
二进制 - |
✕ |
|
|
✕ |
|
数字中的 |
✕ |
|
字符转义 (\t, \b, \n, \r, \', \", \\, \$) |
✓ |
|
Unicode 字面量(例如 \u0000) |
✓ |
|
字符串字面量中的 UTF-16 代理对字符 |
✓ |
|
多行字符串 (""") |
✓ |
|
字符串模板 ($) |
✓ |
|
嵌套字符串模板(例如 |
✓ |
|
语法 |
||
在标识符中使用空格和符号(例如变量/函数名) |
✕ |
|
单行注释 (//) |
✓ |
|
块注释 (/* … */) |
✓ |
|
嵌套块注释 |
✕ |
|
表达式内的额外换行符 |
✓ |
|
运算符 |
||
按位运算(shl, shr, ushr, and, or, xor, inv) |
✕ |
|
布尔逻辑 (&&, ||, !) |
✓ |
|
算术运算 (+, -, *, /, %) |
✓ |
|
比较运算 (<, >, ⇐, >=) |
✓ |
|
相等性 (==, !=) |
✓ |
|
引用相等性 (===, !==) |
✕ |
|
类型检查 (is, !is) |
✓(有区别)除了根类型外,Kotlite 还会检查所有类型参数是否可以分配给主体的类型参数。 Kotlin 不检查。 |
|
类型转换 (as, as?) |
||
In 运算符 (in, !in) |
✓ |
|
To 运算符 ( |
✓ |
|
展开运算符 (*) |
✕ |
|
控制流 |
||
If 表达式 |
✓ |
|
When 表达式,带有可选的 |
✓(有区别)Kotlite 始终需要一个 Kotlin 在不必要时不需要。 |
|
For 循环 |
✓ |
|
While 循环 |
✓ |
|
Do-while 循环 |
✓ |
|
Break 和 Continue |
✓ |
|
正常返回 |
✓ |
|
标记循环 |
✕ |
|
循环的自动标记 |
✕ |
|
Lambda 的自动标记 |
✕ |
|
手动标记 Lambda |
✓ |
|
Break 和 Continue 标记 |
✕ |
|
返回到标记 |
✓ |
|
返回到封闭内联函数外的函数 |
✕ |
|
抛出异常 |
✓ |
|
Try 表达式 |
✓ |
|
Try-catch-finally |
✓ |
|
捕获在解释器范围外抛出的异常 |
✓ |
|
属性 |
||
带有可选初始值的 val/var |
✓ |
|
影子变量 |
✓ |
|
自定义 getter 和 setter |
✕ |
✓ |
自定义 getter 和 setter 的支持字段 |
✕ |
|
|
✕ |
|
委托( |
✕ |
|
解构声明 |
✕ |
|
普通函数 |
✓ |
|
本地函数 |
✓ |
|
带有默认表达式的值参数 |
✓ |
|
命名参数 |
✓ |
|
单表达式函数(例如 |
✓ |
|
可变数量的参数( |
✓(有区别)在 Kotlin 中, 在 Kotlite 中,它以 |
|
重载函数 |
✓ |
|
中缀函数 |
✓ |
|
中缀调用 |
✓ |
|
尾递归函数( |
✕ |
|
内联函数 |
✕ |
|
重载一元运算符 (, -, !, +, --) |
✕ |
|
重载算术二元运算符 (+, -, *, /, %) |
✓ |
|
重载范围运算符 (.., ..<) |
✓ |
|
重载 "in" 运算符 (in, !in) |
✓ |
|
重载索引访问运算符 ([], []=) |
✓ |
|
重载调用运算符 ( |
✕ |
|
重载增强赋值 (+=, -=, *=, /=, %=) |
✓ |
|
重载相等性运算符 (==, !=) |
✓ |
|
重载比较运算符 (>, <, >=, ⇐) |
✓ |
|
挂起函数 |
✕ |
|
包和导入 |
✕ |
|
类基础 |
||
带有可选 val/var 声明的主构造函数 |
✓ |
|
次构造函数 |
✕ |
|
(多个) |
✓ |
|
成员属性 |
✓ |
|
带有自定义 getter 和 setter 的成员属性 |
✓ |
|
带有自定义 getter 和 setter 的成员属性的支持字段 |
✕ |
|
成员函数 |
✓ |
|
重载成员函数 |
✓ |
|
可见性修饰符 (public/private/protected/internal) |
✕ |
|
引用在此类之后声明的其他类 |
✕ |
|
将伴随对象引用存储到字段中 |
✕ |
|
类继承 |
||
将值和类型参数传递给超类构造函数 |
✓ |
|
从超类和接口继承成员 |
✓ |
|
|
✓ |
|
|
✕ |
|
覆盖函数 |
✓(有区别)在 Kotlin 中, 在 Kotlite 中,这是可能的。 未来,Kotlite 可能会遵循 Kotlin。 |
|
覆盖属性 |
✓ |
|
隐式 |
✓ |
|
|
✓ |
|
调用超函数 |
✓ |
|
调用超属性 |
✓ |
|
抽象函数 |
✓ |
|
抽象属性 |
✕ |
|
委托 |
✕ |
|
覆盖来自 "Any" 类的函数 |
✓ |
|
带有菱形的 |
✕ |
|
带有菱形的 |
✕ |
|
类变体 |
||
嵌套类 |
✕ |
|
内部类 |
✕ |
|
抽象类 |
✓ |
|
密封类 |
✕ |
|
枚举类 |
部分在 Kotlite 中,仅支持带有可选属性声明的主构造函数。不支持其他形式的成员声明。 例如,以下是支持的:
|
|
数据类 |
✕ |
|
值类 |
✕ |
|
对象类 |
✕ |
|
伴随对象 |
仅适用于扩展函数和属性 |
|
注解类 |
✕ |
|
匿名类 |
✕ |
|
接口 |
||
抽象函数 |
✓ |
|
带有主体的函数 |
✕ |
|
抽象属性 |
✕ |
|
(多个)接口继承 |
✓ |
|
函数接口( |
✕ |
|
密封接口 |
✕ |
|
扩展 |
||
扩展函数 |
✓ |
|
扩展运算符函数 |
✓ |
|
扩展属性 |
✕ |
✓ |
可空接收者扩展 |
✓ |
|
伴随对象扩展 |
✓ |
|
泛型类型参数作为扩展函数的接收者(例如 |
✓ |
|
作为类成员的扩展函数 |
✓ |
|
解析对超类/接口的扩展函数的调用 |
✓ |
|
类中的类型参数 |
✓ |
|
接口中的类型参数 |
✓ |
|
非类函数中的类型参数 |
✓ |
|
(泛型)类成员函数中的类型参数 |
✓ |
|
扩展函数中的类型参数 |
✓ |
|
嵌套泛型类型 |
✓ |
|
使用类型参数作为扩展函数的接收者 |
✕ |
|
|
✕ |
|
星号投影( |
✓ |
|
类型参数的上界(例如 |
✓ |
|
类型参数的递归上界(例如 |
✓ |
|
肯定非空类型(例如 |
✕ |
|
|
✕ |
|
类型擦除 |
不同在 Kotlin 中,类型参数不会被保留。 在 Kotlite 中,它的行为就像类型参数被擦除一样,但它在运行时被保留。 |
|
未检查转换 |
✓ |
|
下划线作为类型参数 |
✕ |
|
具体化类型参数 |
不,因为没有类型擦除 |
|
类型别名 |
✕ |
|
空值安全 |
||
可空类型(例如 |
✓ |
|
非空类型(例如 |
✓ |
|
安全调用运算符( |
✓ |
|
Elvis 运算符( |
✓ |
|
NPE 运算符( |
✓ |
|
安全转换( |
✓ |
|
Lambda 和高阶函数 |
||
Lambda 表达式 |
✓ |
|
匿名函数 |
✕ |
|
返回和存储 Lambda 字面量 |
✓ |
|
将尾随 Lambda 传递给函数 |
✓ |
|
隐式单个参数 |
✓ |
|
下划线作为未使用的变量名 |
✓ |
|
Lambda 中的解构值参数 |
✕ |
|
访问在封闭闭包中声明的变量和函数 |
✓ |
|
嵌套 Lambda |
✓ |
|
标记 Lambda |
✓ |
|
函数值参数中带有接收者的函数类型(例如 |
✓ |
|
带有接收者的函数字面量(例如 |
✕ |
|
函数引用( |
✕ |
|
执行前检查 |
||
类型检查 |
✓ |
|
检查不存在的变量、函数或类 |
✓ |
|
检查对只读属性的非法写入 |
✓ |
|
检查歧义的函数调用 |
✓ |
|
检查不符合上界条件的类型参数 |
✓ |
|
检测 |
✕ |
|
类型推断 |
||
属性声明的类型 (val/var) |
✓ |
|
if 和 when 表达式的返回类型 |
✓ |
|
单表达式函数的返回类型 |
✓ |
|
推断 Lambda 值参数类型 |
✓ |
|
推断 Lambda 返回类型 |
✓ |
|
泛型函数调用的类型参数 |
✓ |
|
泛型类构造函数的类型参数 |
✓ |
|
泛型扩展函数的接收者 |
✓ |
|
递归地推断嵌套类型 |
✓ |
|
循环类型推断错误检测 |
✓ |
|
在断言非空后识别可空类型为非空 |
✕ |
|
在断言子类型后识别超类型为子类型 |
✕ |
|
解开不必要的安全调用运算符( |
✕ |
|
注解 |
✕ |
|
反射 |
✕ |
|
协程 |
✕ |
|
异步编程 |
✕ |
|
与 Java 和其他语言的互操作性 |
✕ |
|
运行时行为差异
| 代码 | Kotlin 1.9 | Kotlite |
|---|---|---|
带有
as? 运算符的泛型
|
抛出异常:
|
输出:
|
带有
as? 运算符的泛型
|
输出:
|
输出:
|
本地类中的属性解析
|
输出:
|
输出:
|
预期差异
在 Kotlin 中,成员函数的优先级始终高于扩展函数。
目前,由于在 Kotlite 中提供自定义类函数的唯一方法是提供扩展函数,具有以下签名的扩展函数被视为特殊函数,且优先级高于成员函数。在识别特殊函数的过程中不考虑返回类型。
fun equals(Any?)
fun hashCode()
fun toString()
内置和标准库 API
概述
本文档详细介绍 Kotlite 的内置类型和标准库 API。Kotlite 提供了丰富的标准库函数,让你可以进行各种常用操作。
内置类型
Int
整数类型,表示 32 位整数。
val a: Int = 42
val b = 100
val c = -5
常用操作:
- a + b - 加法
- a - b - 减法
- a * b - 乘法
- a / b - 除法
- a % b - 取模
- a.compareTo(b) - 比较
Long
长整数类型,表示 64 位整数。
val a: Long = 42L
val b = 100L
Double
双精度浮点数类型。
val pi: Double = 3.14159
val e = 2.71828
Boolean
布尔类型。
val isTrue: Boolean = true
val isFalse = false
Char
字符类型。
val letterA: Char = 'A'
val newline = '\n'
String
字符串类型。
val greeting: String = "Hello, World!"
val empty = ""
核心库 (Core)
范围函数
Kotlite 提供了常用的范围函数来简化代码。
let
对对象执行操作并返回结果。
val result = "Hello".let {
it.uppercase()
}
// "HELLO"
run
执行代码块并返回结果。
val result = run {
val a = 10
val b = 20
a + b
}
// 30
apply
对对象应用操作并返回对象本身。
val list = mutableListOf<Int>().apply {
add(1)
add(2)
add(3)
}
also
对对象执行额外操作并返回对象本身。
val numbers = listOf(1, 2, 3).also {
println("List: $it")
}
字符串库 (Text)
基本操作
val str = "Hello, World!"
// 获取长度
str.length // 13
// 获取字符
str[0] // 'H'
// 子串
str.substring(0, 5) // "Hello"
字符串转换
val str = "Hello"
// 大小写转换
str.uppercase() // "HELLO"
str.lowercase() // "hello"
// 去除空白
" test ".trim() // "test"
字符串检查
val str = "Hello, World!"
// 包含
str.contains("World") // true
// 前缀/后缀
str.startsWith("Hello") // true
str.endsWith("!") // true
// 是否为空
"".isEmpty() // true
" ".isBlank() // true
字符串分割和连接
// 分割
"a,b,c".split(",") // ["a", "b", "c"]
// 连接
listOf("a", "b", "c").joinToString(",") // "a,b,c"
集合库 (Collections)
List
列表是有序的元素集合。
// 创建列表
val list = listOf(1, 2, 3)
val mutable = mutableListOf("a", "b", "c")
// 访问元素
list[0] // 1
list.first() // 1
list.last() // 3
// 添加元素
mutable.add("d")
mutable.add(0, "x")
// 移除元素
mutable.remove("c")
mutable.removeAt(0)
列表操作
val numbers = listOf(1, 2, 3, 4, 5)
// 映射
numbers.map { it * 2 } // [2, 4, 6, 8, 10]
// 过滤
numbers.filter { it % 2 == 0 } // [2, 4]
// 折叠
numbers.fold(0) { acc, it -> acc + it } // 15
// 遍历
numbers.forEach { println(it) }
// 检查
numbers.any { it > 3 } // true
numbers.all { it > 0 } // true
numbers.none { it < 0 } // true
Map
映射是键值对的集合。
// 创建映射
val map = mapOf("a" to 1, "b" to 2)
val mutable = mutableMapOf("x" to 10, "y" to 20)
// 访问值
map["a"] // 1
map.getOrDefault("c", 0) // 0
// 添加/更新
mutable["z"] = 30
mutable.put("w", 40)
// 移除
mutable.remove("x")
Set
集合是不重复元素的集合。
// 创建集合
val set = setOf(1, 2, 3)
val mutable = mutableSetOf(1, 2, 3)
// 添加/移除
mutable.add(4)
mutable.remove(2)
// 检查
set.contains(2) // true
数学库 (Math)
基本运算
// 绝对值
kotlin.math.abs(-5) // 5
// 最大值/最小值
kotlin.math.max(10, 20) // 20
kotlin.math.min(10, 20) // 10
// 幂运算
kotlin.math.pow(2.0, 3.0) // 8.0
// 平方根
kotlin.math.sqrt(16.0) // 4.0
舍入运算
// 四舍五入
kotlin.math.round(3.7) // 4.0
// 向下/向上取整
kotlin.math.floor(3.7) // 3.0
kotlin.math.ceil(3.1) // 4.0
三角函数
// 正弦/余弦/正切
kotlin.math.sin(kotlin.math.PI / 2) // 1.0
kotlin.math.cos(0.0) // 1.0
kotlin.math.tan(kotlin.math.PI / 4) // 1.0
正则表达式库 (Regex)
创建正则表达式
val regex = Regex("\\d+")
val pattern = Regex("[a-z]+")
匹配操作
val regex = Regex("\\d+")
// 完整匹配
regex.matches("123") // true
regex.matches("abc") // false
// 部分匹配
regex.containsMatchIn("abc123def") // true
// 查找匹配
regex.find("abc123def456")?.value // "123"
regex.findAll("abc123def456").map { it.value }.toList() // ["123", "456"]
替换操作
val regex = Regex("\\d+")
regex.replace("abc123def456", "X") // "abcXdefX"
范围库 (Range)
创建范围
// 范围
val range = 1..10
val untilRange = 1 until 10 // 不包含10
val downTo = 10 downTo 1
// 步长
val step = 1..10 step 2 // 1, 3, 5, 7, 9
范围操作
val range = 1..10
// 包含检查
5 in range // true
// 遍历
for (i in range) {
println(i)
}
// 转换为列表
range.toList() // [1, 2, ..., 10]
IO 库 (IO)
输出
// 打印
println("Hello, World!")
print("Hello")
// 格式化输出
println("Number: %d".format(42))
字节库 (Byte)
字节操作
val byte: Byte = 0x7F
// 位运算
val a: Byte = 0b1010
val b: Byte = 0b1100
a and b // 0b1000
a or b // 0b1110
a xor b // 0b0110
a.inv() // 反转位
KDateTime 库 (日期时间)
日期时间操作
// 获取当前时间
val now = KDateTime.now()
// 访问组件
now.year
now.month
now.dayOfMonth
now.hour
now.minute
now.second
Uuid 库
UUID 生成
// 生成随机 UUID
val uuid = Uuid.randomUuid()
// 转换为字符串
uuid.toString()
// 解析 UUID
Uuid.fromString("550e8400-e29b-41d4-a716-446655440000")
标准库模块
安装所有模块
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
选择性安装模块
val env = ExecutionEnvironment().apply {
install(CoreLibModule())
install(TextLibModule())
install(CollectionsLibModule())
install(MathLibModule())
// 其他模块...
}
可用的模块:
- AllStdLibModules() - 所有模块
- CoreLibModule() - 核心函数
- TextLibModule() - 字符串操作
- CollectionsLibModule() - 集合操作
- MathLibModule() - 数学函数
- RegexLibModule() - 正则表达式
- RangeLibModule() - 范围操作
- IOLibModule() - 输入输出
- ByteLibModule() - 字节操作
- KDateTimeLibModule() - 日期时间
- UuidLibModule() - UUID 生成