Когда использовать методы расширения?

58
6

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

Нормальная функция

fun blah(x: Int) { println(x) }
val f = blah(1)

Метод расширения

fun Int.blah() { println(this) }
val f = 1.blah()

Насколько я понимаю, методы расширения С# работают аналогичным образом.

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

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

спросил(а) 2017-10-27T09:19:00+03:00 2 года, 12 месяцев назад
1
Решение
80

https://kotlinlang.org/docs/reference/extensions.html#extensions-are-resolved-statically

Расширения разрешены статически

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

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

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

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

Я бы порекомендовал вам следующее: всякий раз, когда у вас есть функция, которую вы должны написать как StringUtil.isNullOrEmpty(String) функцию с помощью класса Utility, такого как StringUtil.isNullOrEmpty(String), используйте функции расширения. Используйте остальные как "обычные" функции.

Также прочитайте мотивацию Kotlin для создания расширений: https://kotlinlang.org/docs/reference/extensions.html#motivation

ответил(а) 2017-10-27T09:28:00+03:00 2 года, 12 месяцев назад
42

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

Они в основном используются для двух вещей:

Расширение типов, с которыми у вас нет прямого контроля. Общим примером в С# является функция ForEach(), которая расширяет IEnumerable (базовые типы для списков и т.д.) С помощью метода применения действия ко всем элементам:


public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach (T item in enumeration)
{
action(item);
}
}

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

ответил(а) 2017-10-27T09:36:00+03:00 2 года, 12 месяцев назад
41

Вы пишете расширения, когда у вас нет доступа к исходному коду. В Java вы пишете служебные классы.

public final class BarUtility {
public static int foo(Bar i, int j){
return i.value + j;
}
}

BarUtility.foo(bar, 1);

В Котлине вы пишете метод расширений.

fun Bar.foo(i: Int): Int = value + i
bar.foo(1)

В С# это то же самое, но вы также используете его для реализации метода интерфейса. (Kotlin допускает реализацию метода интерфейса.)

ответил(а) 2017-10-27T09:28:00+03:00 2 года, 12 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема