title | date | author | tags | keywords | categories | reward | reward_title | reward_wechat | reward_alipay | source_url | translator | translator_url |
---|---|---|---|---|---|---|---|---|---|---|---|---|
[译]M8 is out! |
2014-07-01 17:00:00 -0700 |
Hadi Hariri |
官方动态 |
false |
Have a nice Kotlin! |
自上次发布以来,这是一个非常忙碌的几个月,我们一直在努力进行实质性改进,特别是在速度方面。我们对这个版本有很多好处。让我们开始吧
作为第一次了解 Kotlin 的未来反思功能,您现在可以将属性作为 Kotlin 中的一流对象进行访问:
{% raw %}
{% endraw %}var x = 1
fun main(args: Array<String>) {
println(::x.get()) // prints "1"
::x.set(2)
println(x) // prints "2"
}
{% raw %}
{% endraw %}“:: propertyName”语法给出一个属性对象,以便您可以获取或设置其值。您还可以访问该属性的名称(将对各种框架有用)。我们将来会增加更多的功能。 要访问作为课程成员的属性,可以说
{% raw %}
{% endraw %}class A(val p: Int)
fun main(args: Array<String>) {
val prop = A::p
println(prop.get(A(1))) // prints "1"
}
{% raw %}
{% endraw %}当然,它也适用于扩展:
{% raw %}
{% endraw %}val String.lastChar: Char
get() = this[size - 1]
fun main(args: Array<String>) {
println(String::lastChar.get("abc")) // prints "c"
}
{% raw %}
{% endraw %}Kotlin 反思的另一面是它与 Java 的反思的互操作性。例如,要找到一个支持字段或 Java 方法作为 Kotlin 属性的 getter,您可以这样说:
{% raw %}
{% endraw %}import kotlin.reflect.jvm.*
class A(val p: Int)
fun main(args: Array<String>) {
println(A::p.javaGetter) // prints "public final int A.getP()"
println(A::p.javaField) // prints "private final int A.p"
}
{% raw %}
{% endraw %}我们将在未来数月进一步发展反思能力。最终的目标是为框架作者提供真正强大的工具来满足他们的需求。议程上的内容包括适当的 Kotlin 类反省,通过反射使类型可用,将反射功能带入可调用引用(:: functionName)等。敬请关注。
一些增强了内联功能,包括:
-
支持默认参数功能。
-
支持嵌入对象。
为了演示这两个功能,我们来看下面的例子。说,我们有一个 Value 界面:
{% raw %}
{% endraw %}trait Value<V> {
fun get() : V
}
{% raw %}
{% endraw %}现在,我们想创建一个计算值被锁定的值:
{% raw %}
{% endraw %}inline fun <T> guardedValue(
lock: Lock = ReentrantLock(),
compute: () -> T
) : Value<T> {
return object : Value<T> {
override fun get(): T {
return lock.withLock {
compute()
}
}
}
}
{% raw %}
{% endraw %}我们的 guardedValue()是一个内联函数。现在,lock参数具有默认值(为每个值创建一个新的 ReentrantLock)。然后,此函数内的对象表达式“捕获”计算参数,并直接在创建的匿名类内嵌。这导致只有一个类和一个对象每个值发出(并存储),而不是非内联情况的两个类和两个对象。
{% raw %}
{% endraw %}编译器现在会发生错误,当它生成的某些 JVM 签名将会在字节码中发生冲突(以前这可能会导致 ClassFormatError 或意外覆盖超类“方法而不知道)。 例如,以下 Kotlin 代码看起来是无害的,但是断开了 JVM:
{% raw %}
{% endraw %}val x = 1
fun getX() = 1
{% raw %}
{% endraw %}现在,Kotlin 抱怨这个代码:
{% raw %}
{% endraw %}Error:(1, 1) Kotlin: Platform declaration clash:
The following declarations have the same JVM signature (getX()I):
fun <get-x>(): kotlin.Int
fun getX(): kotlin.Int
{% raw %}
{% endraw %}原因是x的 getter 具有相同的名称(getX)和签名(不需要参数,返回 Int)作为其旁边声明的函数,JVM 不允许在类文件中使用这样的东西。 另一种情况是意外覆盖:
{% raw %}
{% endraw %}open class Base {
fun getX() = 1
}
class Derived(val x: Int) : Base()
{% raw %}
{% endraw %}这里,x 的 getter 与 getX()具有相同的签名,但它们现在处于不同的类中,所以 getter 会静默地覆盖该函数,以使 Derived(2).getX()返回 2 而不是 1。 现在编译器抓住了这个错误
{% raw %}
{% endraw %}Error:(1, 15) Kotlin: Accidental override:
The following declarations have the same JVM signature (getX()I):
fun <get-x>(): kotlin.Int
fun getX(): kotlin.Int
{% raw %}
{% endraw %}人们可能会想知道为什么我们不会自动重命名其中一个功能,而不是发出错误?答案在于 Java 互操作性的领域(没有人喜欢编译器发明的名称)和二进制兼容性(事物的名称绝不能静默地改变,或者所有依赖的代码将意外地破坏)。另一方面,您可以使用platformName注释手动指定所需的 JVM 名称:
{% raw %}
{% endraw %}import kotlin.platform.platformName
val x = 1
[platformName("doGetX")]
fun getX() = 1
{% raw %}
{% endraw %}请注意,对于 Kotlin 客户端,此代码不会更改,但 Java 客户端必须使用平台名称(doGetX)而不是 Kotlin 名称(getX)。 警告:这是一个break更改,您现有的一些代码可能需要修复。
除了长期可用的**之外。我们现在支持transient,同步和strictfp作为注释。语义与 Java 类似:
{% raw %}
{% endraw %}class FlagDemo {
volatile var s = ""
transient var list = listOf(1, 2, 3)
strictfp fun math() { /* strict floating-point available here */ }
synchronized fun sync() { /* synchronized on this */ }
}
{% raw %}
{% endraw %}- 生成的委托代码的代码现在工作得更快,并减少内存分配。
- 此外,由于现在正在使用专用的字节码指令,常量的语句更快。
- 您现在可以在 JavaScript 中支持数据类。这意味着您现在可以在使用 JavaScript 中的数据注释以及 Java 中注释类时自动生成 toString,equals 和 hashCode。
- 此外,JavaScript 中还支持 LinkedHashSet 和 LinkedHashMap。
一些语言变化,所有这些变化都是破坏变化,重要的是要注意:
- 私有的一个包现在意味着私有的当前包中的模块。在其他模块中具有相同名称的软件包将不会看到这些定义。请注意,程序包是嵌套的,因此同一个模块中的子包也可以看到 privates。
- 扩展属性不能具有后缀字段。这是从来没有建议过的。
- 如果您发现 Kotlin 允许“@”和“@@”作为标签名称,我们很抱歉告诉您,这不再是这样。
标准库还提供了一些新的功能:
-
添加了 slice()函数,它可以迭代整数,并返回一个包含所述位置元素的列表。
-
join()适用于字符串的 iterables(数组,列表等),并将它们组合成一个字符串
-
joinToString()适用于任何类型的迭代或数组,并且等效于.map {it.toString()} .join()
-
地图现在有重载的函数 contains()。因此,通过惯例,可以实现像“map in map”这样的功能
-
字符串现在可以利用诸如函数之类的集合
-
substringBefore,substringBeforeLast 和 substringAfter,substringAfterLast 允许在某个字符或字符串之前和之后找到字符串。 replaceBefore,replaceBeforeLast 和 replaceAfter,replaceAfterLast 允许在某个字符或字符串之前和之后替换字符串。 appendln 添加到 StringBuilder 一个新的 StringBuilder 函数,它接受一个 String 构建器扩展,允许代码如:
-
val information = StringBuilder { 附加(“第一个条目”) appendln() appendln(“其他一行”) }
12345
val information = StringBuilder {append(“A first entry”)appendln()appendln(“Some other line”)}
- substringBefore,substringBeforeLast 和 substringAfter,substringAfterLast 允许在某个字符或字符串之前和之后找到字符串。
- replaceBefore,replaceBeforeLast 和 replaceAfter,replaceAfterLast 允许在某个字符或字符串之前和之后替换字符串。
- appendln 添加到 StringBuilder
- 一个新的 StringBuilder 函数,它接受一个 String 构建器扩展,允许代码如: