Как я могу предотвратить использование расширения kotlin на моих объектах? - PullRequest
0 голосов
/ 26 октября 2018

Для особых проблем с многопоточностью в моем приложении я создал объект с методом runOrQueue(), который принимает блок.Вот упрощенная версия для иллюстративных целей:

class SpecialThread {
    fun runOrQueue() {}
}

Проблема в том, что когда я пытаюсь написать код с использованием этого метода, среда IDE сначала автоматически завершается до метода расширения Kotlin с именем run(), определенный в стандартной библиотеке:

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {…}

Вот снимок экрана автозаполнения IDE:

enter image description here

Это особенно опасно в контексте моего приложения, так как и run, и runOrQueue будут иметь схожие результаты (оба выполняются с блоком кода), но стандартная версия библиотеки в некоторых ситуациях вылетает,правильно обернут в метод runOrQueue.

Можно ли как-нибудь явно отключить возможность использования расширения run на этом конкретном объекте моего творения?На самом деле, просматривая код, который я написал сам, я уже по ошибке использовал run дважды вместо более длинного имени метода, и это нехорошо.

Ответы [ 3 ]

0 голосов
/ 26 октября 2018

Хотя комментарии о переименовании метода заслуживают внимания, я продолжал пытаться не допустить компиляции неправильного кода и смог достичь компромисса, который может быть обобщен для других возможных столкновений символов в будущем.

Во-первых, чтобы запутать компилятор, к объекту добавлен очень похожий метод:

@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.

Не самая красивая в мире, но она подходит ближе и выполняет свою работу.Или, как сказала бы Салли Амаки, притворяйся, пока не сделаешь .

0 голосов
/ 26 октября 2018

Если вы действительно не хотите переименовывать свой метод, и вы абсолютно уверены, что никогда не будете использовать функцию 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>
0 голосов
/ 26 октября 2018

Боюсь, это не совсем возможно, так как run находится в библиотеке 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.

Написать собственное расширение lint, чтобы пометить использование run как предупреждение или ошибку:

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

EDIT:

Forpas дал еще одно хорошее решение переименовать вашу функцию в queueOrRun. Проблема в этом заключается в ИЛИ, я полагаю, что ваш метод пытается run и возвращается к queue, если это невозможно, поэтому изменение имени функции сделает ее менее понятной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...