如何检查“lateinit”变量是不是已初始化?

Posted

技术标签:

【中文标题】如何检查“lateinit”变量是不是已初始化?【英文标题】: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 【参考方案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 blog 或KEEP proposal 上的公告。

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

Checking whether a lateinit var is initialized Lateinit top-level properties and local variables

【讨论】:

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

Accepted answer 在Kotlin 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

以上是关于如何检查“lateinit”变量是不是已初始化?的主要内容,如果未能解决你的问题,请参考以下文章

Android开发Kotlin检查lateinit变量是否已初始化的方法

lateinit by lazy

如何检查 Perl 标量变量是不是已初始化?

为啥我得到 kotlin.UninitializedPropertyAccessException 即使 lateinit 属性已初始化(可能)

Kotlin类的初始化 ④ ( lateinit 延迟初始化 | ::属性名称.isInitialized 检查属性是否初始化 | lazy 惰性初始化 )

Kotlin类的初始化 ④ ( lateinit 延迟初始化 | ::属性名称.isInitialized 检查属性是否初始化 | lazy 惰性初始化 )