# Kotlin 1.1 的新特性
## 目录
[TOC]
## JavaScrip
从 Kotlin 1.1 开始,JavaScript 目标平台不再当是实验性的。所有语言功能都支持,并且有许多新的工具用于与前端开发环境集成。更详细改动列表,请参见下文。
## 协程(实验性的)
Kotlin 1.1 的关键新特性是*协程*,它带来了 `future`/`await`、 `yield` 以及类似的编程模式的支持。Kotlin 的设计中的关键特性是协程执行的实现是语言库的一部分,而不是语言的一部分,所以你不必绑定任何特定的编程范式或并发库。
协程实际上是一个轻量级的线程,可以挂起并稍后恢复。协程通过[*挂起函数*](https://www.kancloud.cn/alex_wsc/android_kotlin/1318237)支持:对这样的函数的调用可能会挂起协程,并启动一个新的协程,我们通常使用匿名挂起函数(即挂起 lambda 表达式)。
我们来看看在外部库 [kotlinx.coroutines](https://github.com/kotlin/kotlinx.coroutines) 中实现的 `async`/`await`:
```kotlin
// 在后台线程池中运行该代码
fun asyncOverlay() = async(CommonPool) {
// 启动两个异步操作
val original = asyncLoadImage("original")
val overlay = asyncLoadImage("overlay")
// 然后应用叠加到两个结果
applyOverlay(original.await(), overlay.await())
}
// 在 UI 上下文中启动新的协程
launch(UI) {
// 等待异步叠加完成
val image = asyncOverlay().await()
// 然后在 UI 中显示
showImage(image)
}
```
这里,`async { …… }` 启动一个协程,当我们使用 `await()` 时,挂起协程的执行,而执行正在等待的操作,并且在等待的操作完成时恢复(可能在不同的线程上) 。
标准库通过 `yield` 和 `yieldAll` 函数使用协程来支持*惰性生成序列*。在这样的序列中,在取回每个元素之后挂起返回序列元素的代码块,并在请求下一个元素时恢复。这里有一个例子:
```kotlin
import kotlin.coroutines.experimental.*
fun main(args: Array<String>) {
//sampleStart
val seq = buildSequence {
for (i in 1..5) {
// 产生一个 i 的平方
yield(i * i)
}
// 产生一个区间
yieldAll(26..28)
}
// 输出该序列
println(seq.toList())
//sampleEnd
}
```
运行上面的代码以查看结果。随意编辑它并再次运行!
更多信息请参见[协程文档](https://www.kancloud.cn/alex_wsc/android_kotlin/1318237)及[教程](https://www.kotlincn.net/docs/tutorials/coroutines/coroutines-basic-jvm.html)。
请注意,协程目前还是一个**实验性的特性**,这意味着 Kotlin 团队不承诺在最终的 1.1 版本时保持该功能的向后兼容性。
## 其他语言功能
### 类型别名
类型别名允许你为现有类型定义备用名称。这对于泛型类型(如集合)以及函数类型最有用。
这里有几个例子
```kotlin
//sampleStart
typealias OscarWinners = Map<String, String>
fun countLaLaLand(oscarWinners: OscarWinners) =
oscarWinners.count { it.value.contains("La La Land") }
// 请注意,类型名称(初始名和类型别名)是可互换的:
fun checkLaLaLandIsTheBestMovie(oscarWinners: Map<String, String>) =
oscarWinners["Best picture"] == "La La Land"
//sampleEnd
fun oscarWinners(): OscarWinners {
return mapOf(
"Best song" to "City of Stars (La La Land)",
"Best actress" to "Emma Stone (La La Land)",
"Best picture" to "Moonlight" /* …… */)
}
fun main(args: Array<String>) {
val oscarWinners = oscarWinners()
val laLaLandAwards = countLaLaLand(oscarWinners)
println("LaLaLandAwards = $laLaLandAwards (in our small example), but actually it's 6.")
val laLaLandIsTheBestMovie = checkLaLaLandIsTheBestMovie(oscarWinners)
println("LaLaLandIsTheBestMovie = $laLaLandIsTheBestMovie")
}
```
更详细信息请参阅其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/type-aliases.md)。
### 已绑定的可调用引用
现在可以使用 `::` 操作符来获取指向特定对象实例的方法或属性的[成员引用](https://www.kancloud.cn/alex_wsc/android_kotlin/1318347)。以前这只能用 lambda 表达式表示。
这里有一个例子:
```kotlin
//sampleStart
val numberRegex = "\\d+".toRegex()
val numbers = listOf("abc", "123", "456").filter(numberRegex::matches)
//sampleEnd
fun main(args: Array<String>) {
println("Result is $numbers")
}
```
更详细信息请参阅其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/bound-callable-references.md)。
### 密封类和数据类
Kotlin 1.1 删除了一些对 Kotlin 1.0 中已存在的密封类和数据类的限制。现在你可以在同一个文件中的任何地方定义一个密封类的子类,而不只是以作为密封类嵌套类的方式。数据类现在可以扩展其他类。这可以用来友好且清晰地定义一个表达式类的层次结构:
```kotlin
//sampleStart
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
val e = eval(Sum(Const(1.0), Const(2.0)))
//sampleEnd
fun main(args: Array<String>) {
println("e is $e") // 3.0
}
```
更详细信息请参阅其[文档](https://www.kancloud.cn/alex_wsc/android_kotlin/1318307)或者[密封类](https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)及[数据类](https://github.com/Kotlin/KEEP/blob/master/proposals/data-class-inheritance.md)的 KEEP。
### lambda 表达式中的解构
现在可以使用[解构声明](https://www.kancloud.cn/alex_wsc/android_kotlin/1318339)语法来解开传递给 lambda 表达式的参数。
这里有一个例子:
```kotlin
fun main(args: Array<String>) {
//sampleStart
val map = mapOf(1 to "one", 2 to "two")
// 之前
println(map.mapValues { entry ->
val (key, value) = entry
"$key -> $value!"
})
// 现在
println(map.mapValues { (key, value) -> "$key -> $value!" })
//sampleEnd
}
```
更详细信息请参阅其[文档](https://www.kancloud.cn/alex_wsc/android_kotlin/1318339)及其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/destructuring-in-parameters.md)。
### 下划线用于未使用的参数
对于具有多个参数的 lambda 表达式,可以使用 `_` 字符替换不使用的参数的名称:
```kotlin
fun main(args: Array<String>) {
val map = mapOf(1 to "one", 2 to "two")
//sampleStart
map.forEach { _, value -> println("$value!") }
//sampleEnd
}
```
这也适用于[解构声明](https://www.kancloud.cn/alex_wsc/android_kotlin/1318339):
```kotlin
data class Result(val value: Any, val status: String)
fun getResult() = Result(42, "ok").also { println("getResult() returns $it") }
fun main(args: Array<String>) {
//sampleStart
val (_, status) = getResult()
//sampleEnd
println("status is '$status'")
}
```
更详细信息请参阅其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/underscore-for-unused-parameters.md)。
### 数字字面值中的下划线
正如在 Java 8 中一样,Kotlin 现在允许在数字字面值中使用下划线来分隔数字分组:
```kotlin
//sampleStart
val oneMillion = 1_000_000
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
//sampleEnd
fun main(args: Array<String>) {
println(oneMillion)
println(hexBytes.toString(16))
println(bytes.toString(2))
}
```
更详细信息请参阅其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/underscores-in-numeric-literals.md)。
### 对于属性的更短语法
对于没有自定义访问器、或者将 getter 定义为表达式主体的属性,现在可以省略属性的类型:
```kotlin
//sampleStart
data class Person(val name: String, val age: Int) {
val isAdult get() = age >= 20 // 属性类型推断为 “Boolean”
}
//sampleEnd
fun main(args: Array<String>) {
val akari = Person("Akari", 26)
println("$akari.isAdult = ${akari.isAdult}")
}
```
### 内联属性访问器
如果属性没有幕后字段,现在可以使用 `inline` 修饰符来标记该属性访问器。这些访问器的编译方式与[内联函数](https://www.kancloud.cn/alex_wsc/android_kotlin/1318318)相同。
```kotlin
//sampleStart
public val <T> List<T>.lastIndex: Int
inline get() = this.size - 1
//sampleEnd
fun main(args: Array<String>) {
val list = listOf('a', 'b')
// 其 getter 会内联
println("Last index of $list is ${list.lastIndex}")
}
```
你也可以将整个属性标记为 `inline`——这样修饰符应用于两个访问器。更详细信息请参阅其[文档](https://www.kancloud.cn/alex_wsc/android_kotlin/1318318)及其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/inline-properties.md)。
### 局部委托属性
现在可以对局部变量使用[委托属性](https://www.kancloud.cn/alex_wsc/android_kotlin/1318315)语法。一个可能的用途是定义一个延迟求值的局部变量:
```kotlin
import java.util.Random
fun needAnswer() = Random().nextBoolean()
fun main(args: Array<String>) {
//sampleStart
val answer by lazy {
println("Calculating the answer...")
42
}
if (needAnswer()) { // 返回随机值
println("The answer is $answer.") // 此时计算出答案
}
else {
println("Sometimes no answer is the answer...")
}
//sampleEnd
}
```
更详细信息请参阅其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/local-delegated-properties.md)。
### 委托属性绑定的拦截
对于[委托属性](https://www.kancloud.cn/alex_wsc/android_kotlin/1318315),现在可以使用 `provideDelegate` 操作符拦截委托到属性之间的绑定。
例如,如果我们想要在绑定之前检测属性名称,我们可以这样写:
```kotlin
class ResourceLoader<T>(id: ResourceID<T>) {
operator fun provideDelegate(thisRef: MyUI, property: KProperty<*>): ReadOnlyProperty<MyUI, T> {
checkProperty(thisRef, property.name)
…… // 属性创建
}
private fun checkProperty(thisRef: MyUI, name: String) { …… }
}
fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { …… }
class MyUI {
val image by bindResource(ResourceID.image_id)
val text by bindResource(ResourceID.text_id)
}
```
`provideDelegate` 方法在创建 `MyUI` 实例期间将会为每个属性调用,并且可以立即执行必要的验证。
更详细信息请参阅其[文档](https://www.kancloud.cn/alex_wsc/android_kotlin/1318315)。
### 泛型枚举值访问
现在可以用泛型的方式来对枚举类的值进行枚举:
```kotlin
//sampleStart
enum class RGB { RED, GREEN, BLUE }
inline fun <reified T : Enum<T>> printAllValues() {
print(enumValues<T>().joinToString { it.name })
}
//sampleEnd
fun main(args: Array<String>) {
printAllValues<RGB>() // 输出 RED, GREEN, BLUE
}
```
### 对于 DSL 中隐式接收者的作用域控制
`@DslMarker` 注解允许限制来自 DSL 上下文中的外部作用域的接收者的使用。考虑那个典型的 [HTML 构建器示例](type-safe-builders.html):
```kotlin
table {
tr {
td { + "Text" }
}
}
```
在 Kotlin 1.0 中,传递给 `td` 的 lambda 表达式中的代码可以访问三个隐式接收者:传递给 `table`、`tr`和 `td` 的。 这允许你调用在上下文中没有意义的方法——例如在 `td` 里面调用 `tr`,从而在 `<td>` 中放置一个 `<tr>` 标签。
在 Kotlin 1.1 中,你可以限制这种情况,以使只有在 `td` 的隐式接收者上定义的方法会在传给 `td` 的 lambda 表达式中可用。你可以通过定义标记有 `@DslMarker` 元注解的注解并将其应用于标记类的基类。
更详细信息请参阅其[文档](https://www.kancloud.cn/alex_wsc/android_kotlin/1318349)及其 [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/scope-control-for-implicit-receivers.md)。
### `rem` 操作符
`mod` 操作符现已弃用,而使用 `rem` 取代。动机参见[这个问题](https://youtrack.jetbrains.com/issue/KT-14650)。
## 标准库
### 字符串到数字的转换
在 String 类中有一些新的扩展,用来将它转换为数字,而不会在无效数字上抛出异常:
`String.toIntOrNull(): Int?`、 `String.toDoubleOrNull(): Double?` 等。
```kotlin
val port = System.getenv("PORT")?.toIntOrNull() ?: 80
```
还有整数转换函数,如 `Int.toString()`、 `String.toInt()`、 `String.toIntOrNull()`,每个都有一个带有 `radix` 参数的重载,它允许指定转换的基数(2 到 36)。
### onEach()
`onEach` 是一个小、但对于集合和序列很有用的扩展函数,它允许对操作链中的集合/序列的每个元素执行一些操作,可能带有副作用。
对于迭代其行为像 `forEach` 但是也进一步返回可迭代实例。 对于序列它返回一个包装序列,它在元素迭代时延迟应用给定的动作。
```kotlin
inputDir.walk()
.filter { it.isFile && it.name.endsWith(".txt") }
.onEach { println("Moving $it to $outputDir") }
.forEach { moveFile(it, File(outputDir, it.toRelativeString(inputDir))) }
```
### also()、takeIf() 和 takeUnless()
这些是适用于任何接收者的三个通用扩展函数。
`also` 就像 `apply`:它接受接收者、做一些动作、并返回该接收者。二者区别是在 `apply` 内部的代码块中接收者是 `this`,而在 `also` 内部的代码块中是 `it`(并且如果你想的话,你可以给它另一个名字)。当你不想掩盖来自外部作用域的 `this` 时这很方便:
```kotlin
class Block {
lateinit var content: String
}
//sampleStart
fun Block.copy() = Block().also {
it.content = this.content
}
//sampleEnd
// 使用“apply”代替
fun Block.copy1() = Block().apply {
this.content = this@copy1.content
}
fun main(args: Array<String>) {
val block = Block().apply { content = "content" }
val copy = block.copy()
println("Testing the content was copied:")
println(block.content == copy.content)
}
```
`takeIf` 就像单个值的 `filter`。它检测接收者是否满足该谓词,并在满足时返回该接收者否则不满足时返回 `null`。
结合 elvis-操作符和及早返回,它允许编写如下结构:
```kotlin
val outDirFile = File(outputDir.path).takeIf { it.exists() } ?: return false
// 对现有的 outDirFile 做些事情
```
```kotlin
fun main(args: Array<String>) {
val input = "Kotlin"
val keyword = "in"
//sampleStart
val index = input.indexOf(keyword).takeIf { it >= 0 } ?: error("keyword not found")
// 对输入字符串中的关键字索引做些事情,鉴于它已找到
//sampleEnd
println("'$keyword' was found in '$input'")
println(input)
println(" ".repeat(index) + "^")
}
```
`takeUnless` 与 `takeIf` 相同,只是它采用了反向谓词。当它 _不_ 满足谓词时返回接收者,否则返回 `null`。因此,上面的示例之一可以用 `takeUnless` 重写如下:
```kotlin
val index = input.indexOf(keyword).takeUnless { it < 0 } ?: error("keyword not found")
```
当你有一个可调用的引用而不是 lambda 时,使用也很方便:
```kotlin
private fun testTakeUnless(string: String) {
//sampleStart
val result = string.takeUnless(String::isEmpty)
//sampleEnd
println("string = \"$string\"; result = \"$result\"")
}
fun main(args: Array<String>) {
testTakeUnless("")
testTakeUnless("abc")
}
```
### groupingBy()
此 API 可以用于按照键对集合进行分组,并同时折叠每个组。 例如,它可以用于计算文本中字符的频率:
```kotlin
fun main(args: Array<String>) {
val words = "one two three four five six seven eight nine ten".split(' ')
//sampleStart
val frequencies = words.groupingBy { it.first() }.eachCount()
//sampleEnd
println("Counting first letters: $frequencies.")
// 另一种方式是使用“groupBy”和“mapValues”创建一个中间的映射,
// 而“groupingBy”的方式会即时计数。
val groupBy = words.groupBy { it.first() }.mapValues { (_, list) -> list.size }
println("Comparing the result with using 'groupBy': ${groupBy == frequencies}.")
}
```
### Map.toMap() 和 Map.toMutableMap()
这俩函数可以用来简易复制映射:
```kotlin
class ImmutablePropertyBag(map: Map<String, Any>) {
private val mapCopy = map.toMap()
}
```
### Map.minus(key)
运算符 `plus` 提供了一种将键值对添加到只读映射中以生成新映射的方法,但是没有一种简单的方法来做相反的操作:从映射中删除一个键采用不那么直接的方式如 `Map.filter()` 或 `Map.filterKeys()`。
现在运算符 `minus` 填补了这个空白。有 4 个可用的重载:用于删除单个键、键的集合、键的序列和键的数组。
```kotlin
fun main(args: Array<String>) {
//sampleStart
val map = mapOf("key" to 42)
val emptyMap = map - "key"
//sampleEnd
println("map: $map")
println("emptyMap: $emptyMap")
}
```
### minOf() 和 maxOf()
这些函数可用于查找两个或三个给定值中的最小和最大值,其中值是原生数字或 `Comparable` 对象。每个函数还有一个重载,它接受一个额外的 `Comparator` 实例,如果你想比较自身不可比的对象的话。
```kotlin
fun main(args: Array<String>) {
//sampleStart
val list1 = listOf("a", "b")
val list2 = listOf("x", "y", "z")
val minSize = minOf(list1.size, list2.size)
val longestList = maxOf(list1, list2, compareBy { it.size })
//sampleEnd
println("minSize = $minSize")
println("longestList = $longestList")
}
```
### 类似数组的列表实例化函数
类似于 `Array` 构造函数,现在有创建 `List` 和 `MutableList` 实例的函数,并通过调用 lambda 表达式来初始化每个元素:
```kotlin
fun main(args: Array<String>) {
//sampleStart
val squares = List(10) { index -> index * index }
val mutable = MutableList(10) { 0 }
//sampleEnd
println("squares: $squares")
println("mutable: $mutable")
}
```
### Map.getValue()
`Map` 上的这个扩展函数返回一个与给定键相对应的现有值,或者抛出一个异常,提示找不到该键。如果该映射是用 `withDefault` 生成的,这个函数将返回默认值,而不是抛异常。
```kotlin
fun main(args: Array<String>) {
//sampleStart
val map = mapOf("key" to 42)
// 返回不可空 Int 值 42
val value: Int = map.getValue("key")
val mapWithDefault = map.withDefault { k -> k.length }
// 返回 4
val value2 = mapWithDefault.getValue("key2")
// map.getValue("anotherKey") // <- 这将抛出 NoSuchElementException
//sampleEnd
println("value is $value")
println("value2 is $value2")
}
```
### 抽象集合
这些抽象类可以在实现 Kotlin 集合类时用作基类。对于实现只读集合,有 `AbstractCollection`、 `AbstractList`、 `AbstractSet` 和 `AbstractMap`,而对于可变集合,有 `AbstractMutableCollection`、 `AbstractMutableList`、 `AbstractMutableSet` 和 `AbstractMutableMap`。在 JVM 上,这些抽象可变集合从 JDK 的抽象集合继承了大部分的功能。
### 数组处理函数
标准库现在提供了一组用于逐个元素操作数组的函数:比较(`contentEquals` 和 `contentDeepEquals`),哈希码计算(`contentHashCode` 和 `contentDeepHashCode`),以及转换成一个字符串(`contentToString` 和`contentDeepToString`)。它们都支持 JVM(它们作为 `java.util.Arrays` 中的相应函数的别名)和 JS(在Kotlin 标准库中提供实现)。
```kotlin
fun main(args: Array<String>) {
//sampleStart
val array = arrayOf("a", "b", "c")
println(array.toString()) // JVM 实现:类型及哈希乱码
println(array.contentToString()) // 良好格式化为列表
//sampleEnd
}
```
## JVM 后端
### Java 8 字节码支持
Kotlin 现在可以选择生成 Java 8 字节码(命令行选项 `-jvm-target 1.8` 或者 Ant/Maven/Gradle 中的相应选项)。目前这并不改变字节码的语义(特别是,接口和 lambda 表达式中的默认方法的生成与 Kotlin 1.0 中完全一样),但我们计划在以后进一步使用它。
### Java 8 标准库支持
现在有支持在 Java 7 和 8 中新添加的 JDK API 的标准库的独立版本。如果你需要访问新的 API,请使用 `kotlin-stdlib-jre7` 和 `kotlin-stdlib-jre8` maven 构件,而不是标准的 `kotlin-stdlib`。这些构件是在 `kotlin-stdlib` 之上的微小扩展,它们将它作为传递依赖项带到项目中。
### 字节码中的参数名
Kotlin 现在支持在字节码中存储参数名。这可以使用命令行选项 `-java-parameters` 启用。
### 常量内联
编译器现在将 `const val` 属性的值内联到使用它们的位置。
### 可变闭包变量
用于在 lambda 表达式中捕获可变闭包变量的装箱类不再具有 volatile 字段。此更改提高了性能,但在一些罕见的使用情况下可能导致新的竞争条件。如果受此影响,你需要提供自己的同步机制来访问变量。
### javax.scripting 支持
Kotlin 现在与[javax.script API](https://docs.oracle.com/javase/8/docs/api/javax/script/package-summary.html)(JSR-223)集成。
其 API 允许在运行时求值代码段:
```kotlin
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
engine.eval("val x = 3")
println(engine.eval("x + 2")) // 输出 5
```
关于使用 API 的示例项目参见[这里](https://github.com/JetBrains/kotlin/tree/master/libraries/examples/kotlin-jsr223-local-example)。
### kotlin.reflect.full
[为 Java 9 支持准备](https://blog.jetbrains.com/kotlin/2017/01/kotlin-1-1-whats-coming-in-the-standard-library/),在 `kotlin-reflect.jar` 库中的扩展函数和属性已移动到 `kotlin.reflect.full` 包中。旧包(`kotlin.reflect`)中的名称已弃用,将在Kotlin 1.2 中删除。请注意,核心反射接口(如 `KClass`)是 Kotlin 标准库(而不是 `kotlin-reflect`)的一部分,不受移动影响。
## JavaScript 后端
### 统一的标准库
Kotlin 标准库的大部分目前可以从代码编译成 JavaScript 来使用。
特别是,关键类如集合(`ArrayList`、 `HashMap` 等)、异常(`IllegalArgumentException` 等)以及其他几个关键类(`StringBuilder`、 `Comparator`)现在都定义在 `kotlin` 包下。在 JVM 平台上,一些名称是相应 JDK 类的类型别名,而在 JS 平台上,这些类在 Kotlin 标准库中实现。
### 更好的代码生成
JavaScript 后端现在生成更加可静态检测的代码,这对 JS 代码处理工具(如minifiers、 optimisers、 linters 等)更加友好。
### `external` 修饰符
如果你需要以类型安全的方式在 Kotlin 中访问 JavaScript 实现的类,你可以使用 `external` 修饰符写一个 Kotlin 声明。(在 Kotlin 1.0 中,使用了 `@native` 注解。)与 JVM 目标平台不同,JS 平台允许对类和属性使用 external 修饰符。例如,可以按以下方式声明 DOM `Node` 类:
```kotlin
external class Node {
val firstChild: Node
fun appendChild(child: Node): Node
fun removeChild(child: Node): Node
// 等等
}
```
### 改进的导入处理
现在可以更精确地描述应该从 JavaScript 模块导入的声明。
如果在外部声明上添加 `@JsModule("<模块名>")` 注解,它会在编译期间正确导入到模块系统(CommonJS或AMD)。例如,使用 CommonJS,该声明会通过 `require(……)` 函数导入。
此外,如果要将声明作为模块或全局 JavaScript 对象导入,可以使用 `@JsNonModule` 注解。
例如,以下是将 JQuery 导入 Kotlin 模块的方法:
```kotlin
external interface JQuery {
fun toggle(duration: Int = definedExternally): JQuery
fun click(handler: (Event) -> Unit): JQuery
}
@JsModule("jquery")
@JsNonModule
@JsName("$")
external fun jquery(selector: String): JQuery
```
在这种情况下,JQuery 将作为名为 `jquery` 的模块导入。或者,它可以用作 $-对象,这取决于Kotlin编译器配置使用哪个模块系统。
你可以在应用程序中使用如下所示的这些声明:
```kotlin
fun main(args: Array<String>) {
jquery(".toggle-button").click {
jquery(".toggle-panel").toggle(300)
}
}
```
- 前言
- Kotlin简介
- IntelliJ IDEA技巧总结
- idea设置类注释和方法注释模板
- 像Android Studion一样创建工程
- Gradle
- Gradle入门
- Gradle进阶
- 使用Gradle创建一个Kotlin工程
- 环境搭建
- Androidstudio平台搭建
- Eclipse的Kotlin环境配置
- 使用IntelliJ IDEA
- Kotlin学习路线
- Kotlin官方中文版文档教程
- 概述
- kotlin用于服务器端开发
- kotlin用于Android开发
- kotlin用于JavaScript开发
- kotlin用于原生开发
- Kotlin 用于数据科学
- 协程
- 多平台
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 开始
- 基本语法
- 习惯用法
- 编码规范
- 基础
- 基本类型
- 包与导入
- 控制流
- 返回与跳转
- 类与对象
- 类与继承
- 属性与字段
- 接口
- 可见性修饰符
- 扩展
- 数据类
- 密封类
- 泛型
- 嵌套类
- 枚举类
- 对象
- 类型别名
- 内嵌类
- 委托
- 委托属性
- 函数与Lambda表达式
- 函数
- Lambda表达式
- 内联函数
- 集合
- 集合概述
- 构造集合
- 迭代器
- 区间与数列
- 序列
- 操作概述
- 转换
- 过滤
- 加减操作符
- 分组
- 取集合的一部分
- 取单个元素
- 排序
- 聚合操作
- 集合写操作
- List相关操作
- Set相关操作
- Map相关操作
- 多平台程序设计
- 平台相关声明
- 以Gradle创建
- 更多语言结构
- 解构声明
- 类型检测与转换
- This表达式
- 相等性
- 操作符重载
- 空安全
- 异常
- 注解
- 反射
- 作用域函数
- 类型安全的构造器
- Opt-in Requirements
- 核心库
- 标准库
- kotlin.test
- 参考
- 关键字与操作符
- 语法
- 编码风格约定
- Java互操作
- Kotlin中调用Java
- Java中调用Kotlin
- JavaScript
- 动态类型
- kotlin中调用JavaScript
- JavaScript中调用kotlin
- JavaScript模块
- JavaScript反射
- JavaScript DCE
- 原生
- 并发
- 不可变性
- kotlin库
- 平台库
- 与C语言互操作
- 与Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 调试
- FAQ
- 协程
- 协程指南
- 基础
- 取消与超时
- 组合挂起函数
- 协程上下文与调度器
- 异步流
- 通道
- 异常处理与监督
- 共享的可变状态与并发
- Select表达式(实验性)
- 工具
- 编写kotlin代码文档
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin与OSGI
- 编译器插件
- 编码规范
- 演进
- kotlin语言演进
- 不同组件的稳定性
- kotlin1.3的兼容性指南
- 常见问题
- FAQ
- 与Java比较
- 与Scala比较(官方已删除)
- Google开发者官网简介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin样品
- Kotlin零基础到进阶
- 第一阶段兴趣入门
- kotlin简介和学习方法
- 数据类型和类型系统
- 入门
- 分类
- val和var
- 二进制基础
- 基础
- 基本语法
- 包
- 示例
- 编码规范
- 代码注释
- 异常
- 根类型“Any”
- Any? 可空类型
- 可空性的实现原理
- kotlin.Unit类型
- kotlin.Nothing类型
- 基本数据类型
- 数值类型
- 布尔类型
- 字符型
- 位运算符
- 变量和常量
- 语法和运算符
- 关键字
- 硬关键字
- 软关键字
- 修饰符关键字
- 特殊标识符
- 操作符和特殊符号
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- this关键字
- super关键字
- 操作符重载
- 一元操作符
- 二元操作符
- 字符串
- 字符串介绍和属性
- 字符串常见方法操作
- 字符串模板
- 数组
- 数组介绍创建及遍历
- 数组常见方法和属性
- 数组变化以及下标越界问题
- 原生数组类型
- 区间
- 正向区间
- 逆向区间
- 步长
- 类型检测与类型转换
- is、!is、as、as-运算符
- 空安全
- 可空类型变量
- 安全调用符
- 非空断言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函数
- 函数式编程概述
- OOP和FOP
- 函数式编程基本特性
- 组合与范畴
- 在Kotlin中使用函数式编程
- 函数入门
- 函数作用域
- 函数加强
- 命名参数
- 默认参数
- 可变参数
- 表达式函数体
- 顶层、嵌套、中缀函数
- 尾递归函数优化
- 函数重载
- 控制流
- if表达式
- when表达式
- for循环
- while循环
- 循环中的 Break 与 continue
- return返回
- 标签处返回
- 集合
- list集合
- list集合介绍和操作
- list常见方法和属性
- list集合变化和下标越界
- set集合
- set集合介绍和常见操作
- set集合常见方法和属性
- set集合变换和下标越界
- map集合
- map集合介绍和常见操作
- map集合常见方法和属性
- map集合变换
- 集合的函数式API
- map函数
- filter函数
- “ all ”“ any ”“ count ”和“ find ”:对集合应用判断式
- 别样的求和方式:sumBy、sum、fold、reduce
- 根据人的性别进行分组:groupBy
- 扁平化——处理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 区间、数组、集合之间转换
- 面向对象
- 面向对象-封装
- 类的创建及属性方法访问
- 类属性和字段
- 构造器
- 嵌套类(内部类)
- 枚举类
- 枚举类遍历&枚举常量常用属性
- 数据类
- 密封类
- 印章类(密封类)
- 面向对象-继承
- 类的继承
- 面向对象-多态
- 抽象类
- 接口
- 接口和抽象类的区别
- 面向对象-深入
- 扩展
- 扩展:为别的类添加方法、属性
- Android中的扩展应用
- 优化Snackbar
- 用扩展函数封装Utils
- 解决烦人的findViewById
- 扩展不是万能的
- 调度方式对扩展函数的影响
- 被滥用的扩展函数
- 委托
- 委托类
- 委托属性
- Kotlin5大内置委托
- Kotlin-Object关键字
- 单例模式
- 匿名类对象
- 伴生对象
- 作用域函数
- let函数
- run函数
- with函数
- apply函数
- also函数
- 标准库函数
- takeIf 与 takeUnless
- 第二阶段重点深入
- Lambda编程
- Lambda成员引用高阶函数
- 高阶函数
- 内联函数
- 泛型
- 泛型的分类
- 泛型约束
- 子类和子类型
- 协变与逆变
- 泛型擦除与实化类型
- 泛型类型参数
- 泛型的背后:类型擦除
- Java为什么无法声明一个泛型数组
- 向后兼容的罪
- 类型擦除的矛盾
- 使用内联函数获取泛型
- 打破泛型不变
- 一个支持协变的List
- 一个支持逆变的Comparator
- 协变和逆变
- 第三阶段难点突破
- 注解和反射
- 声明并应用注解
- DSL
- 协程
- 协程简介
- 协程的基本操作
- 协程取消
- 管道
- 慕课霍丙乾协程笔记
- Kotlin与Java互操作
- 在Kotlin中调用Java
- 在Java中调用Kotlin
- Kotlin与Java中的操作对比
- 第四阶段专题练习
- 朱凯Kotlin知识点总结
- Kotlin 基础
- Kotlin 的变量、函数和类型
- Kotlin 里那些「不是那么写的」
- Kotlin 里那些「更方便的」
- Kotlin 进阶
- Kotlin 的泛型
- Kotlin 的高阶函数、匿名函数和 Lambda 表达式
- Kotlin协程
- 初识
- 进阶
- 深入
- Kotlin 扩展
- 会写「18.dp」只是个入门——Kotlin 的扩展函数和扩展属性(Extension Functions / Properties)
- Kotlin实战-开发Android