• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

The Four Dots of Mystery

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,483
Баллы
155
Every so often, you might come across the strange sight of :: in your Kotlin code.

This cheeky little four-eyed fella is the Callable Reference Operator. Implementing it creates a callable reference from a function, property or class.

What is a callable reference?


A callable reference is a separate object that represents a function, property or class. It does not execute immediately, rather it holds the reference until the moment that it is invoked.

For example:



fun add(a: Int, b: Int): Int {
return a + b
}

val calculateNow = add(3, 5)
// ?? this variable makes a direct call to the 'add' function.
// It will execute immediately

val calculateLater = ::add
// ?? this variable makes a callable reference of the 'add' function.
// It will only execute when the variable is invoked (as below ??)

calculateLater(2, 5)




The Kotlin.reflect API


The reference we create by using the Callable Reference Operator is always an object from the kotlin.reflect API (eg. an instance of KFunction, KProperty, or KClass). We can see this when we hover over our callable reference in the IDE:


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



KFunction2 tells us we are representing a function that has two parameters.
<Int, Int, Int> tells us the parameters are of type Int, as is the return type.

When might we use the Callable Reference Operator?


A callable reference is 'first-class' which means that it can be passed as an argument, stored in a variable, or returned from a function - just as any other data type - a Boolean, String, Int, etc.. This makes it particularly useful for passing into higher order functions.

The Callable Reference Operator in action


In the below examples, I demonstrate how the Callable Reference Operator can be used as a concise alternative to passing lambdas to functions in a few different case scenarios.

A function reference (::functionName)



fun isOdd(x: Int) = x % 2 != 0
val numbers = listOf(1, 2, 3)

numbers.filter(::isOdd) // [1,3]

// the above line does the same as ??

numbers.filter { isOdd(it) } // [1,3]





A property reference (ClassName::propertyName)



val strings = listOf("a", "bc", "def")

strings.map(String::length) // [1, 2, 3]

// the above line does the same as ??

strings.map { it.length } // [1, 2, 3]





Constructor reference (::ClassName)



data class Person(val name: String, val age: Int)

val personGenerator: (String, Int) -> Person = ::Person

// the above line does the same as ??

val personGeneratorUsingLambda: (String, Int) -> Person = { nameParam, ageParam ->
Person(nameParam, ageParam)
}

// we can also treat ::Person as a first class value in the following higher-order function

fun createPeopleFromData(data: List<Pair<String, Int>>, personGenerator: (String, Int) -> Person): List<Person> {
return data.map { (name, age) -> personGenerator(name, age)}
}

val listOfPeople = listOf(
"Sidney" to 2,
"Alf" to 5,
"Morag" to 10
)

val people = createPeopleFromData(listOfPeople, ::Person)

// the above line does the same as ??

val peopleUsingLambda = createPeopleFromData(listOfPeopleData) { nameParam, ageParam ->
Person(nameParam, ageParam)
}





In this last example, you can really see how the code becomes more concise when we use the Callable Reference Operator.

Conclusion


Using the Callable Reference Operator is pretty neat. However, a clever, concise way of programming is only useful if it's also easy to understand for any other engineer who might come across it.

I don't come across the Callable Reference Operator very much in production code which implies one of two things: either there is a lack of knowledge / confidence in using it or that the knowledge is there but that engineers find it less intuitive or think it makes code less readable.

Personally, I don't currently read the Callable Reference Operator as fluently as I might read a lambda. But this way of thinking will no doubt start to wane as I gain experience around using (and reading) this operator. I will certainly be looking out for it more in code and also look forward to utilising it more in my own work.



Источник:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу