Kotlin:const val vs val

H.N*_*yen 30 android kotlin

我理解在Kotlin const val中用于声明常量并且val用于只读属性.但是,我想知道以下情况,哪一个更适合使用.

假设我有一个片段需要一个密钥用于saveInstanceStaterestoreInstanceState.我想知道以下两个选项中哪一个更好:

选项1:

class MyFragment {
    private val MY_KEY = "my_key"
    ...
}
Run Code Online (Sandbox Code Playgroud)

选项2:

private const val MY_KEY = "my_key" // declared in the same file.

class MyFragment {
    ...
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢#option 2,因为它清楚地表明它MY_KEY是一个常量,并且值是在编译时确定的.但是,由于它是在顶层声明的,因此它需要在编译的java代码中创建一个类,即MyFragmentKt(假设文件名是MyFragment.kt).在#option 1中,没有生成额外的类,虽然它MY_KEY的值将在运行时分配而不是常量,但在这种特定情况下它的使用方式没有区别.

所以虽然我个人更喜欢#option 2,但我的分析让我觉得#option 1并不差,如果不是更好的话.我只是想知道其他开发人员如何考虑这个问题以及#option 2是否还有其他任何我没有想过的好处.谢谢.

Mar*_*nik 19

每次编写(非内联)lambda表达式时,都创建了另一个类.与此相比,创建一个用于保存顶级声明的类似乎很小.

此外,如果你有在顶层是一个常量声明,它会内联到每个使用地点(通过规范),因此拥有的类本身将成为ProGuard的的最小化未引用的,因此靶向.它很可能不会出现在你的制作APK中.

  • 我一直在思考相反的情况,你是对的!这是一篇解释它的帖子:https://marcin-chwedczuk.github.io/lambda-expressions-in-kotlin (4认同)
  • 感谢@Marko,该常量将被内联,并且生成的类稍后将被 Proguard 排除,这一事实使得 #Option 2 在这里成为明显的赢家(IMO) (2认同)

Moi*_*ira 13

这两个选项之间不仅存在语义差异.

选项1(val在类中)是一个实例字段.

选项2(顶级const val)是顶级"静态"成员(粗略地说,因为static在Kotlin中不存在.)

这就是MyFragmentKt生成类的原因:顶级成员被编译成名称的类[Filename]Kt.

我会考虑第三种选择:

class MyFragment {
    companion object {
        private const val MY_KEY = "my_key"
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,MY_KEY(来自Java)是类的static成员MyFragment,因为它JvmStatic是为const变量推断的.将Companion生成一个类(但它将为空).

由于你的原始方法是类中的一个字段,我觉得companion object/ static常量可能更好.

更多关于companion objects vs Java的信息static

  • 虽然完全正确且合法,但我认为这对于 Kotlin 来说是不惯用的,用户应该只使用顶级声明的伟大且自由的功能,而不用担心对最终产品的非常微小或不存在的影响。 (2认同)
  • 实际上,`private` 顶级声明具有不同的语义并且不会成为包的成员,因为它们不能在声明它们的文件之外访问。这也意味着 `private` 顶级声明自然地与该文件耦合。Kotlin 中的文件是紧耦合实体的封装单元,与 Java 不同,它可以包含多个类。 (2认同)
  • 在 Kotlin 中,我已经转变为“属于文件”的思维方式,而不是仅仅属于一个类。任何没有类实例就可以存在的东西都不应该真正属于该类,这只是 Java 强加给我们的思维方式的残余。我经常将几个紧密耦合的类分组到一个文件中,然后我可以在顶层声明它们共享的所有内容。在 Java 中你甚至不能这样做。 (2认同)