“This is the sixth day of my participation in the First Challenge 2022. For details: First Challenge 2022”

preface

When reading Kotlin’s code, I often see the :: symbol. The technical term for this symbol is called member reference. It can be used in code to simplify the code.

The body of the

Although this is very familiar, but let’s start with the simple, need to understand why the design.

Transfer function optimization

Let’s use the familiar sort function sortBy to define the People class:

// Test the code
data class People(val name: String.val age: Int){
    // Custom sort criteria
    fun getMax() : Int{
        return age * 10 + name.length
    }
}
Copy the code

Then let’s sort:

val people = People("zyh".10)
val people1 = People("zyh1".100)
val peopleList = arrayListOf(people,people1)
// Pass sortBy a lambda
peopleList.sortBy { people -> people.getMax() }
Copy the code

Here we pass a lambda to the sortBy function. Since the sortBy function is inline, the lambda passed to it will be inline, but suppose there is a problem now that these lambdas are already defined as function variables. For example, I define a top-level function:

// defines a top-level function
fun getMaxSort(people: People): Int{
    return (people.age) * 10 + people.name.length
}
Copy the code

Or the sort condition has been defined as a variable value:

// Sort conditions
val condition = { people: People -> people.getMax() }
Copy the code

So if I want to sort again, I have to write this:

// Call the function
peopleList.sortBy { getMaxSort(it) }
// Pass parameters
peopleList.sortBy(condition)
Copy the code

Then we can optimize this by using the member reference :: symbol:

// The top-level function getMaxSort is called directly
peopleList.sortBy(::getMaxSort)
// The getMax function of the People class is called directly
peopleList.sortBy(People::getMax)
Copy the code

This looks like syntactic sugar, which simplifies the code.

Member references:

Have you ever wondered why we’re using the :: notation to convert a function to a value, first of all we use

val condition = { people: People -> people.getMax() }
Copy the code

In this case, condition is a function of type, which we discussed earlier. Kotlin supports full function types, and higher-order functions can be lambda, but getMaxSort() is a function, not a value. Unless you wrap another layer around it to form a lambda, so condition is passed into sortBy(), and getMaxSort(it) wraps another layer in the form of a lambda.

But when you use ::, you convert the function to a value like People::getMax and that’s a value that represents the getMax function inside People.

And ::getMaxSort is also a value that represents the getMaxSort function.

Using range

The previous two examples show the scope of such member references. One is a function or attribute of a class, and the other is the top-level function, which has no class name and can be omitted.

The binding reference

People::getMax = People::getMax = People::getMax = People::getMax

// Define a people instance
val people = People("zyh".10)
// Use member references to convert functions to values
val ageFun = People::age
val age = ageFun(people)
// Use directly on object instances ::
val ageValue = people::age
Copy the code

AgeFun is a function type, while ageValue is an int value. AgeValue is a function type.

conclusion

To summarize, a member reference is simple: it converts a function to a value, which can be thought of as a function type.

However, the real principle is not so simple, it is not using lambda to cover the function with another layer, here should be reflection related knowledge, we will talk about the principle in detail later, just happen to have reflection related articles, you can like, follow a wave.