Intereting Posts
Как создать карту из списка с помощью внутреннего списка с помощью Kotlin Как переключить видимость FAB с другим FAB Kotlin – Кинжал 2 – это не инъекционные объекты CellCache неожиданно появляется в TableView с tornadoFX Возможно ли лениво инициализировать свойство и утверждать его? Android Espresso – как запустить настройку только один раз для всех тестов открыть alertDialog в kotlin, как установить оба сообщения с помощью переключателей Серия Autosize ScatterChart Повторение текстуры в области текстуры Как сохранить тип объекта для интеллектуального каста при возврате Any Kotlin возвращает тот же объект из метода Factory Повторное соединение RxJava на подключаемом наблюдаемом не работает Ошибка сборки приложения Kotlin из-за «Не удалось инициализировать класс com.intellij.ide.highlighter.JavaFileType» Какая версия Dokka идет с какой версией Kotlin? RxJava 2 требует другого типа возвращаемого типа, чем RxJava 1 (Kotlin)

Расширение Kotlin Any? .toString ()

Я пытался использовать функции расширения в Котлине.

class ExtensionExample() { var name: String? = null fun Any?.toString() : String { if (this == null) { return "Value is null" } return "Value is not null" } } 

Когда я печатаю переменную имени, как показано ниже

 println(ExtensionExample().name.toString()) 

Он должен печатать как

 Value is null 

Но он не печатает, как я ожидал. Он печатает только null .

Может кто-нибудь объяснить, пожалуйста?

Функции расширения имеют области действия . Вот почему он недоступен вне класса ExtensionExample .

Обычно функции расширения определяются как функции верхнего уровня. То есть, они, как правило, принадлежат вне класса .

Расширение toString определено в ExtensionExample . Это возможно , но это означает, что он доступен только в рамках этого класса и только этого класса .

Ваш main метод, вероятно, является функцией верхнего уровня (а не членом этого класса), поэтому он не имеет доступа к этой функции расширения.

Только другие члены могут получить доступ к этой функции расширения:

 class ExtensionExample { var name: String? = null fun Any?.toString(): String { return if (this == null) "Value is null" else "Value is not null" } fun foo() { println(name.toString()) } } fun main(args: Array<String>) { ExtensionExample().foo() } 

prints "Value is null"

Попробуйте прямо сейчас!

Причина компиляции заключается в том, что метод toString который вызывается, является методом Any?.toString из kotlin-stdlib . То есть этот метод уже существует .

fun Any?.toString(): String

Возвращает строковое представление объекта. Может быть вызван с нулевым приемником, и в этом случае он возвращает строку «null».

Извлеките функцию расширения из класса . Затем ваша функция расширения скроет расширение stdlib, и любой вызов в том же пакете, который явно не импортирует kotlin.toString будет использовать вашу функцию.

Вот рабочая версия вашего кода :

 class ExtensionExample { var name: String? = null } fun Any?.toString(): String { return if (this == null) "Value is null" else "Value is not null" } fun main(args: Array<String>) { println(ExtensionExample().name.toString()) } 

prints "Value is null" , как вы хотели.

Попробуйте прямо сейчас!


Обратите внимание, что вы не можете скрыть функцию-член с помощью функции расширения. То есть,

 class Test { fun a() { println("a") } } fun Test.a() { println("b") } ... Test().a() 

приведет к печати «а».

Единственная причина, почему ваш Any?.toString работает (после выхода из класса) – это Any? не имеет членов, поскольку это не класс, а тип с нулевым значением с классом Any . Уже существующий метод toString также является расширением, поэтому ваши не скрываются от каких-либо членов.

Определение функции расширения внутри класса:

Если вы хотите оставить определение toString() в ExtensionExample , вы можете использовать его только там:

 class ExtensionExample() { var name: String? = null // uses the toString() extension function defined in ExtensionExample fun useToString() = name.toString() fun Any?.toString(): String { if (this == null) { return "inside: Value is null" } return "inside: Value is not null" } } 

Эта

 // uses the version of toString() defined in the Kotlin Standard library println(ExtensionExample().name.toString()) // uses the inside version of toString() println(ExtensionExample().useToString()) 

распечатает

ноль
внутри: значение равно null

Определение функции расширения вне класса:

Но если вы хотите использовать его снаружи, вам нужно переместить его на улицу:

 class ExtensionExample() { var name: String? = null // uses the toString() extension function defined in ExtensionExample fun useToString() = name.toString() fun Any?.toString(): String { if (this == null) { return "inside: Value is null" } return "inside: Value is not null" } } fun Any?.toString(): String { if (this == null) { return "outside: Value is null" } return "outside: Value is not null" } 

Эта

 // uses the outside version of toString() which overrides the one from the Kotlin Standard library println(ExtensionExample().name.toString()) // uses the inside version of toString() println(ExtensionExample().useToString()) 

будет печатать:

снаружи: значение равно null
внутри: значение равно null

Если класс имеет функцию-член, и определена функция расширения, которая имеет тот же тип приемника, одно и то же имя и применима к заданным аргументам, член всегда выигрывает.

Ваш метод расширения не может затенять встроенный метод toString в классе Any ( Object ).

Что касается вызова toString по типу с нулевым значением, этот метод уже находится в среде выполнения Kotlin:

 /** * Returns a string representation of the object. Can be called with a null receiver, in which case * it returns the string "null". */ public fun Any?.toString(): String 

См. Также документы о разрешении расширений.