【问题标题】:How to check if a "lateinit" variable has been initialized?如何检查“lateinit”变量是否已初始化?
【发布时间】:2016-10-03 18:39:32
【问题描述】:

我想知道是否有办法检查lateinit 变量是否已初始化。例如:

class Foo() {

    private lateinit var myFile: File

    fun bar(path: String?) {
        path?.let { myFile = File(it) }
    }

    fun bar2() {
        myFile.whateverMethod()
        // May crash since I don't know whether myFile has been initialized
    }
}

【问题讨论】:

  • 也许您需要使属性为空(将类型更改为File?),然后检查它是否为空?
  • 好吧,我确实试过了,它会成功,但是我必须将allSeries var 编辑为seriesDir?.listFiles()?.map { it.name }?.toTypedArray(),这不是很“漂亮”
  • 你可以做一个普通的旧空检查,智能转换会让它更漂亮。 if (seriesDir != null) {allSeries = seriesDir.listFiles().map { it.name }.toTypedArray()}
  • 请考虑接受更多最新的answer

标签: kotlin


【解决方案1】:

这会起作用

if (::list.isInitialized) {
 //true
} 
else {
//false
}

【讨论】:

    【解决方案2】:

    对我来说有效

    if (::file.isInitialized) {
     //true
    } 
    else {
    //false
    }
    

    【讨论】:

      【解决方案3】:

      使用.isInitialized 属性可以检查lateinit 变量的初始化状态。

      if (::file.isInitialized) {
          // File is initialized
      } else {
          // File is not initialized
      }
      

      【讨论】:

      • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review
      • @gforce301 它将明确用于检查。
      • 嗯,这是在具有 Kotlin 版本 1.3 的 Android Studio 上对我有用的唯一答案
      • @gforce301 为什么这不能回答问题?原来的问题变了吗?现在好像可以回答了……
      【解决方案4】:

      如果你在一个类中有lateinit 属性,需要检查它是否是从另一个类初始化的

      if(foo::file.isInitialized) // this wouldn't work
      

      我发现的解决方法是创建一个函数来检查属性是否已初始化,然后您可以从任何其他类调用该函数。

      示例:

      class Foo() {
      
          private lateinit var myFile: File
      
          fun isFileInitialised() = ::file.isInitialized
      }
      
       // in another class
      class Bar() {
      
          val foo = Foo()
      
          if(foo.isFileInitialised()) // this should work
      }
      

      【讨论】:

      • 您需要添加一个函数来检查是否已初始化,这有点荒谬。
      【解决方案5】:

      您可以通过以下方式轻松做到这一点:

      ::variableName.isInitialized
      

      this::variableName.isInitialized
      

      但是,如果您在侦听器或内部类中,请执行以下操作:

      this@OuterClassName::variableName.isInitialized
      

      注意:如果您将上述语句写在声明变量的同一个文件(同一类或内部类)中,则上述语句可以正常工作,但如果您想检查其他类的变量,这将不起作用(可以是超类或任何其他实例化的类),例如:

      class Test {
          lateinit var str:String
      }
      

      并检查 str 是否已初始化:

      我们在这里做什么:检查isInitialized 字段strTest 类在Test2 类中。 我们得到一个错误,此时无法访问 var 的支持字段。 检查已经提出的question

      【讨论】:

      • 正是我正在寻找的东西,并直接将我指向正确的方向
      • 这应该是详细程度的公认答案:)
      【解决方案6】:

      Kotlin 1.2 中有一个lateinit 改进,允许直接检查lateinit 变量的初始化状态:

      lateinit var file: File    
      
      if (this::file.isInitialized) { ... }
      

      请参阅JetBrains blogKEEP proposal 上的公告。

      更新: Kotlin 1.2 已经发布。您可以在此处找到lateinit 增强功能:

      【讨论】:

      • @fer.marino:嗯,Kotlin 1.2 实际上允许您将lateinit 也用于局部变量,请参阅kotlinlang.org/docs/reference/…
      • this::lateinitVar.isInitialized
      • :: 前面的file 是什么意思?
      • @MalwinderSingh 它创建一个成员引用或一个类引用。
      • 我们如何检查本地lateinit,其中this 是不同的东西?
      【解决方案7】:

      Accepted answerKotlin 1.3+ 中给我一个编译器错误,我必须在:: 之前明确提及this 关键字。下面是工作代码。

      lateinit var file: File
      
      if (this::file.isInitialized) {
      
          // file is not null
      }
      

      【讨论】:

      • 当我使用这个检查时,我使用了一个本地初始化变量,它给出了一个错误,比如未解析的引用
      【解决方案8】:
      kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized
      

      字节码说……等等等等……

      public final static synthetic access$getClientKeypair$p(Lcom/takharsh/ecdh/MainActivity;)Ljava/security/KeyPair;
      
      `L0
      LINENUMBER 11 L0
      ALOAD 0
      GETFIELD com/takharsh/ecdh/MainActivity.clientKeypair : Ljava/security/KeyPair;
      DUP
      IFNONNULL L1
      LDC "clientKeypair"
      INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwUninitializedPropertyAccessException (Ljava/lang/String;)V
          L1
      ARETURN
      

      L2 本地变量 $this Lcom/takharsh/ecdh/MainActivity; L0 L2 0 最大堆叠 = 2 MAXLOCALS = 1

      Kotlin 为同一实例创建一个额外的局部变量并检查它是否为 null,如果为 null 则抛出 'throwUninitializedPropertyAccessException' 否则返回本地对象。 以上字节码解释here 解决方案 从 kotlin 1.2 开始,它允许使用 .isInitialized 来检查天气 lateinit var 是否已初始化。

      【讨论】:

        【解决方案9】:

        尝试使用它,如果未初始化,您将收到UninitializedPropertyAccessException

        lateinit 专门用于在构造之后但在实际使用之前(大多数注入框架使用的模型)初始化字段的情况。 如果这不是您的用例,lateinit 可能不是正确的选择。

        编辑:根据你想做的事情,这样的事情会更好:

        val chosenFile = SimpleObjectProperty<File?>
        val button: Button
        
        // Disables the button if chosenFile.get() is null
        button.disableProperty.bind(chosenFile.isNull())
        

        【讨论】:

        • 我有一个 JavaFX 应用程序,并且我有一个按钮,除非变量(lateinit)已被初始化,否则该按钮将始终处于禁用状态。换句话说:只要变量尚未初始化,我希望按钮被禁用。有什么好的方法吗?
        • @MathewHany 如何正常初始化?您可能想查看属性 getter/setter 和 SimpleBooleanProperty,您可以将其绑定到按钮的 disabled 属性
        • 更具体地说,我有一个包含 4 个按钮的简单应用程序,第一个按钮将打开一个 DirectoryChooser 对话框,其他 3 个按钮将被禁用,当用户选择目录时,所有其他按钮按钮将可供用户使用。
        • @MathewHany 您可以使用 SimpleObjectProperty 来保存所选文件,然后使用 isNull 绑定来禁用其他按钮。
        • kotlinlang.org/docs/reference/… xsveda 答案是最新的
        【解决方案10】:

        要检查 lateinit var 是否已初始化或未在对该属性的引用上使用 .isInitialized

        if (foo::bar.isInitialized) {
            println(foo.bar)
        }
        

        此检查仅适用于可通过词法访问的属性,即以相同类型或外部类型之一声明,或在同一文件的顶层声明。

        【讨论】:

        • :: 前面的bar 是什么意思?
        • @Malwinder Singh “创建成员引用或类引用” - Kotlin Doc
        猜你喜欢
        • 2019-03-10
        • 1970-01-01
        • 2011-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-24
        • 2022-12-03
        • 1970-01-01
        相关资源
        最近更新 更多