title | date | author | tags | keywords | categories | reward | reward_title | reward_wechat | reward_alipay | source_url | translator | translator_url |
---|---|---|---|---|---|---|---|---|---|---|---|---|
[译]Kotlin M11 is Out! |
2015-03-19 10:27:00 -0700 |
Andrey Breslav |
官方动态 |
false |
Have a nice Kotlin! |
今天,我们发布了一个新的里程碑:Kotlin M11,带来了诸如次要构造器等久经久待的功能,第一眼就是对 Kotlin 的真正反映**支持。
M11 带来了不少语言变化,其中有些则是破坏旧的做事方式的改变和/或弃用。您的某些代码可能会中断,但我们已尽力使您的过渡路径尽可能顺利。
Android 开发人员最期待这个功能,因为在 Android 上分类标准视图类需要有多个构造函数。现在你可以这样做:
{% raw %}
{% endraw %}class MyView : View {
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
// ...
}
constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) {}
}
{% raw %}
{% endraw %}另一个改变,也与构造函数有关,它是使用软关键字init
的初始化程序块前缀。
这种变化的主要原因是,以前使用的语法(在一个类体中表示为初始化程序块的只是花括号)在初始化程序跟随一个属性声明(这是很常见的))时并没有太好的效果:
{% raw %}
{% endraw %}class Foo {
val bar = baz() // ERROR here
{
// pre-M11 initializer
}
}
{% raw %}
{% endraw %}对baz()
的调用报告了一个错误,因为初始化器看起来像一个传递给它的尾随的 lambda。唯一的解决方法是在属性初始化器之后放一个分号,这在 Kotlin 看起来很不自然。所以,由于 M11,我们在初始化程序块之前需要使用init
:
{% raw %}
{% endraw %}class Foo {
val bar = baz()
init {
// initializer
}
}
{% raw %}
{% endraw %}旧的语法已弃用,即您会收到警告,而不是错误。此外,IDE 提供了一个 Alt + Enter 快速修复操作,将旧的语法转换为新的语法,可以批量更新整个项目。 看到 用户文档 更多细节。
大家可能知道,Kotlin 类没有静态成员。相反,可能会有一个与类关联的特殊单例对象
,我们用来调用“class object”‐一个相当不幸的术语。所以,我们有点重新设计了这个概念, 与你的帮助 ,为其选择另一个名称:伴侣对象。
不幸的措辞不是这种变化的唯一原因。事实上,我们重新设计了这个概念,使其与普通物体更为统一。
请注意,类可以(并且总是可以)嵌套到它中的许多对象(通常的,命名的单例):
{% raw %}
{% endraw %}class KotlinClass {
object Obj1 { ... }
object Obj2 { ... }
...
}
{% raw %}
{% endraw %}由于 M11 可以使用companion
修饰符声明其中一个对象,这意味着可以通过类名直接访问其成员:
{% raw %}
{% endraw %}class KotlinClass {
object Obj1 { ... }
companion object Obj2 { ... }
...
}
{% raw %}
{% endraw %}访问Obj1
的成员需要资格:KotlinClass.Obj1.foo()
。对于Obj2
的成员,对象名称是可选的:KotlinClass.foo()
。
最后一步:可以省略协同对象的名称(在这种情况下,编译器将使用默认名称Companion
):
{% raw %}
{% endraw %}class KotlinClass {
object Obj1 { ... }
companion object { ... }
...
}
{% raw %}
{% endraw %}现在,您仍然可以通过包含类的名称来引用其成员:KotlinClass.foo()
,或通过完整的资格:KotlinClass.Companion.foo()
。
正如你所看到的,与我们以前使用的类对象不同,伴随对象与普通对象完全一致。
另一个重要的好处是,现在每个对象都有一个名字*(当省略一个协同对象的名称时,再次使用Companion
),启用协同对象书写扩展功能:
{% raw %}
{% endraw %}fun KotlinClass.Companion.bar() { ... }
{% raw %}
{% endraw %}请参阅用户文档 这里 。
Kotlin 具有更高阶的功能,这意味着你可以传递一个函数作为一个值。在 M11 之前,有两种获取这些值的方法:lambda 表达式(例如{x - > x + 1}
)和可调用引用(例如MyClass :: myFun
) 。 M11 引入了一个新的,如果你想到的话,这是非常合乎逻辑的:
{% raw %}
{% endraw %}val f = fun (x: Int): Int { return x + 1 }
{% raw %}
{% endraw %}因此,您可以使用其传统句法形式的函数作为值。看到 用户文档 和 规格文件 更多细节。
除其他功能外,函数表达式使我们能够在 lambdas 的参数中支持多声明。最终目标(尚未实现)是能够以下列语法过滤列表:
{% raw %}
{% endraw %}pairs.filter { (a, b) -> a != b }
{% raw %}
{% endraw %}这里,(a,b)
是一个 多声明 ,即a
获取每个Pair
对象的第一个组件,并且b
获得第二个组件。目前,不支持多声明,但是我们不推荐使用 lambdas 的一些语法形式将其放在 M12 中,并使多声明语法成为可能。
什么是不推荐的:
- 指定羔羊的返回类型,例如{(a:Int):Int - > a + 1}
- 指定 lambdas 的接收器类型:{Int。(a:Int) - > this + a}
- 对于 lambdas 参数名称使用括号:{(a,b) - > a + b}
每当你真的需要其中之一时,请切换到使用函数表达式。 IDE 提供了快速修复,自动迁移代码。
长久以来,在 lambdas 中使用return
表达式有一个限制:只有当 lambda 具有显式的返回类型时才允许使用local return
指定。这是由类型推理算法的限制引起的。现在,限制被删除,我们可以自由地使用本地退货:
{% raw %}
{% endraw %}list.map {
if (it < 10) return@map DEFAULT
...
}
{% raw %}
{% endraw %}导入是 IDE 用户最不可见的语言功能之一,但它对工具的工作方式以及用户偶尔也有很大的影响。 在 M11 中,我们将* -imports(也称为“按需导入”)的顺序不重要,并进行了一些其他调整,使我们能够在 IDE 中实现对导入指令的高效自动管理。
实现 Kotlin 特定的反射(而不是让您在 Kotlin 类上使用 Java 反射)是一个长期运行的项目,需要在编译器中进行大量的工作。基本上,我们必须考虑到大部分的编译器,并将其作为运行时的一部分。这包括:从二进制文件中加载 Kotlin 特定的元数据,将 Kotlin 符号表示为对象(历史上我们称之为描述符),将 Java 声明加载为 Kotlin(因为 Kotlin 反射也适用于 Java 对象)等等。 最后,我们介绍这项工作的第一个结果:通过编译器附带的一个新的 kotlin-reflection.jar 提供内省属性的能力(即将添加更多的功能)。
我们分开运送kotlin-reflect.jar
(不是kotlin-runtime.jar
的一部分),因为它现在相当大:大约 1.8MB。我们将考虑缩小其大小,但可能总是相当可观,因此让每个人总是运用它的应用程序不是一个选择(特别是对于 Android 开发人员)。
因此,如果您使用属性文字(:: propertyName
),则可能需要将此 jar 添加到类路径中。如果没有,M11 编译器会产生错误,但稍后这个要求将会放宽。 IDE 将为您提供一个快速修复操作,将 jar 自动添加到您的项目中。
要获取 Kotlin 中的类的反射对象,请使用以下语法:
{% raw %}
{% endraw %}val c = MyClass::class
{% raw %}
{% endraw %}你可以得到一个KClass&lt; MyClass&gt;
的例子。得到它的属性。
看到更多的 用户文档 。
Kotlin 反射 API 适用于 Kotlin 和 Java 类,您可以从 Kotlin“转换”为 Java 反射对象并返回。例如,您可以说kClass.java
并获取一个java.lang.Class
实例,反之亦然:jlClass.kotlin
给你一个KClass
实例。
和往常一样,Java 互操作是我们的首要任务,这一次我们正在改进我们发货的平台类型功能 M9 :现在,编译器发出警告滥用 Java 值注释为@Nullable
和@NotNull
。这并不像以前在 M9 之前那样严格,但是也不会像往常一样破裂。
下一步是以安全的方式发布 Java 可空性错误(从而总是可以合理地修复错误),这是为下一个里程碑计划的。
Android 用户的好消息:M11 带来了一个有用的扩展,使得 Kotlin 中的 Android 开发更容易。
我们都知道findViewById()
。这是一个臭名昭着的错误和不愉快的代码,很难阅读和支持。在 Java 中,解决这个问题的方法是通过库来实现 牛油刀 和 AndroidAnnotations ,依靠 JSR 269 ,但它是一个javac
特定的 API,并且在 Kotlin(尚)中不支持。
自从 M11 以来,Kotlin 有自己的解决方案findViewById()
问题,这不需要 JSR 269:Kotlin 编译器的新的kotlin-android-extensions
插件允许你使用零额外的用户代码(无注释或其他类似的东西)和不需要运行时库,以类型安全的方式访问视图。
要使用此扩展,您需要在 Gradle 构建中启用它,并在 IDE 中安装扩展插件。查看更多 这里 。
IntelliJ IDEA 的更多改进和功能
以下重构和意图现已可用:
- 介绍物业 能够引入属性并定义是否需要初始化程序,getter 或 lazy 属性
- 使用 Java Interop 创建 现在可以在 Kotlin 文件中使用的 Java 类型上调用“从使用创建”。
- 接收机到参数转换 变更签名重构的特殊情况,从而可以将参数重构为接收器,从而允许 将接收到类型 T 的参数的函数转换为 T 的扩展函数。它还允许相反,从而可以将接收器转换为参数。