Функции расширения котлина против функций-членов?

Мне известно, что функции расширения используются в Kotlin для расширения функциональности класса (например, из библиотеки или API).

Однако есть ли какие-либо преимущества с точки зрения читабельности / структуры кода при использовании функций расширения:

class Foo { ... }

fun Foo.bar() {
    // Some stuff
}

В отличие от функций-членов:

class Foo {

    ...

    fun bar() {
        // Some stuff
    }
}

?

Есть ли рекомендуемая практика?


person Farbod Salamat-Zadeh    schedule 08.11.2017    source источник
comment
comment
Здесь вы можете увидеть, как компилируется функция расширения youtube.com/watch?v=wAQCs8- a6mg   -  person Javier Antón    schedule 16.06.2021


Ответы (4)


С моей точки зрения, есть две веские причины использовать функции расширения:

  1. Чтобы «расширить» поведение класса, вы не являетесь автором / не можете изменить (и где наследование не имеет смысла или невозможно).

  2. Чтобы предоставить объем для определенных функций. Например, функция расширения может быть объявлена ​​как автономная функция, и в этом случае ее можно использовать везде. Или вы можете объявить его как (частную) функцию-член другого класса, и в этом случае ее можно использовать только внутри этого класса.

Похоже, что # 1 в вашем случае не беспокоит, так что на самом деле это скорее # 2.

person Oliver Charlesworth    schedule 08.11.2017
comment
Да, я являюсь первоначальным автором класса (это для личного проекта), поэтому №1 не вызывает беспокойства. Не могли бы вы объяснить, что именно вы имеете в виду, говоря о возможностях конкретной функции? Спасибо. - person Farbod Salamat-Zadeh; 08.11.2017
comment
@ FarbodSalamat-Zadeh - Я добавил небольшую деталь к пункту 2 - дайте мне знать, если это поможет прояснить ситуацию. - person Oliver Charlesworth; 08.11.2017
comment
Спасибо, отлично! - person Farbod Salamat-Zadeh; 08.11.2017
comment
Вы можете найти подробное объяснение здесь о №2. - person BakaWaii; 08.11.2017

Когда использовать функции-члены

Вам следует использовать функции-члены, если применимо все следующее:

  • Код изначально написан на Котлине.
  • Вы можете изменить код
  • Метод имеет смысл использовать из любого другого кода.

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

Вам следует использовать функции расширения, если применимо любое из следующего:

  • Код изначально был написан на Java, и вы хотите добавить методы, написанные на Kotlin.
  • Вы не можете изменить исходный код
  • Вам нужна специальная функция, которая имеет смысл только для определенной части кода.

Почему?

Как правило, функции-члены легче найти, чем функции расширения, поскольку они гарантированно относятся к тому классу, членом которого они являются (или суперклассу / интерфейсу).

Их также не нужно импортировать во весь код, который их использует.

person jrtapsell    schedule 08.11.2017

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

Базовый пример будет примерно таким:

// Strings.kt
fun String.isEmail() : Boolean {
    // check for email pattern and return true/false
}

Этот код можно записать как служебную функцию на Java следующим образом:

class StringUtils {
    public static boolean isEmail(String email) {
        // check for email pattern and return true/false
    }
}

По сути, он делает то, что вызов той же функции с объектом, который вы вызываете, будет передан в качестве первого параметра аргументу. Подобно той же функции, которую я привел в Java.

Если вы хотите вызвать функцию расширения, созданную в kotlin из java, вам необходимо передать вызывающего в качестве первого аргумента. Нравится,

StringsKt.isEmail("[email protected]")

Согласно документации,

Расширения фактически не изменяют классы, которые они расширяют. Определяя расширение, вы не вставляете новые члены в класс, а просто делаете новые функции вызываемыми с точечной нотацией для переменных этого типа.

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

Когда создавать функции расширения?

  • Когда у вас нет доступа к этому классу. Когда этот класс принадлежит какой-то библиотеке, которую вы не создали.
  • Для примитивных типов. Int, Float, String и т. Д.

Другая причина для использования функции расширения заключается в том, что вам не нужно расширять этот класс, чтобы использовать методы, как если бы они принадлежали этому классу (но фактически не являются его частью).

Надеюсь, это немного проясняет вам ...

person kirtan403    schedule 11.11.2017

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

Я бы предпочел использовать функции расширения для data classes. Мои рассуждения чисто философские, data classes следует использовать только как носители данных, они не должны нести состояние и сами по себе ничего не должны делать. Вот почему я думаю, что вам следует использовать функцию расширения, если вам нужно написать функцию вокруг data class.

person P. Habzansky    schedule 16.06.2021