如何防止在我的对象上使用kotlin扩展名?

时间:2018-10-26 10:00:21

标签: android-studio kotlin

对于我的应用程序中的特殊线程问题,我使用<form method="post" url="{ '/url1' }"> </form> <form method="post" url="{ '/url2' }"> </form> <button type="submit">Submit</button> 方法创建了一个接受块的对象。这是出于说明目的的简化版本:

runOrQueue()

问题是,当我尝试使用此方法编写代码时,IDE首先自动完成到标准库中定义的Kotlin extension method named run()

class SpecialThread {
    fun runOrQueue() {}
}

这是IDE自动完成功能的屏幕截图:

enter image description here

在我的应用程序上下文中,这特别危险,因为@kotlin.internal.InlineOnly public inline fun <T, R> T.run(block: T.() -> R): R {…} run的结果都相似(都运行一段代码),但是标准库版本在某些情况下会崩溃,并正确包装在runOrQueue方法中。

有什么方法可以明确禁用在创建的这个特定对象上使用runOrQueue扩展名的可能性吗?实际上,回顾我自己编写的代码,我已经错误地两次使用run而不是更长的方法名,这是不好的。

3 个答案:

答案 0 :(得分:3)

如果您确实真的不想重命名方法,并且绝对确定您永远不会使用run函数...

实际上,您可以通过点击建议旁边的意图操作图标来从自动完成中排除任何方法:

Exclude from completion

Settings中,您可以在Editor -> General -> Auto Import下找到,然后在Exclude from import and completion下找到。例如,要排除内置的run函数,您可以通过上述意图或手动添加以下条目:

List of exclusions

如果将此项目作为范围,也可以将排除项签入VCS,您将在.idea/codeInsightSettings.xml下找到它,该项目将包含这些相应的内容以排除run,这很容易说明:

<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="JavaProjectCodeInsightSettings">
    <excluded-names>
      <name>kotlin.run</name>
    </excluded-names>
  </component>
</project>

答案 1 :(得分:2)

尽管重命名该方法的注释值得,但我一直在尝试防止错误代码编译并设法达成妥协,这可能会在将来推广到其他可能的符号冲突

首先,为了使编译器 混乱,向对象添加了一个非常相似的方法:

@Deprecated(level = DeprecationLevel.ERROR,
        message = "This is not the method you are looking for (waves hand)",
        replaceWith = ReplaceWith("runOrQueue()"))
fun <T, R> run(block: T.() -> R): R {
    TODO("Don't use this")
}

这与标准库run()并不完全相同,因此,当您开始在IDE中键入内容时,您仍然会得到一个关于标准库的建议,另一个关于对象方法的建议。幸运的是,即使使用了自动完成版本,由于有两种非常相似的run()方法,编译器会抱怨模棱两可。

实际上,在添加此方法并重建源代码之后,编译器捕获了另外两个错误实例:

e: PasswordPresenter.kt: (181, 49): Using 'run(T.() -> R): R' is an error. This is not the method you are looking for (waves hand)
e: PasswordPresenter.kt: (181, 49): Type inference failed: Not enough information to infer parameter T in fun <T, R> run(block: T.() -> R): R
Please specify it explicitly.

e: PasswordPresenter.kt: (258, 33): Using 'run(T.() -> R): R' is an error. This is not the method you are looking for (waves hand)
e: PasswordPresenter.kt: (258, 33): Type inference failed: Not enough information to infer parameter T in fun <T, R> run(block: T.() -> R): R
Please specify it explicitly.

这不是世界上最漂亮的,但是它可以接近并完成工作。或如萨莉·阿玛基(Sally Amaki)所说的fake it till you make it

答案 2 :(得分:1)

恐怕这是不可能的,因为运行在std库中,并且定义为任何类型的扩展:

/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

一些选项:

对于您不希望使用run的代码库部分,请改用Java编写(因为Kotlin和Java是完全可插入的)。这种解决方案并不理想。

当您指run时不要写runOrQueue

编写自定义的棉绒扩展名,以将run的使用情况标记为警告或错误:

https://developer.android.com/studio/write/lint

编辑:

Forpas提供了另一个很好的解决方案,可以将您的函数重命名为queueOrRun。这个问题是OR,我想您的方法尝试进行run并且仅在不可能的情况下才退回到queue,因此更改函数名称将使其不太清楚它的作用