preface

Even if 10 o ‘clock off work every day, even if the demand is a lot, I also want to use this decayed voice shout out: I want to learn, I want to write an article!!

Several features for quick start Kotlin

Fully understand Kotlin, fast writing business

Quickly switch to Kotlin for Android mode

Let’s talk about coroutines in Kotlin. Nice

Another Kotlin article, why… It’s because of work. There is no doubt that the best way to learn is through official documentation. However, I personally feel that official documents are more or less inefficient.

Chinese Official Documents

Therefore, this article outputs the basic Kotlin language learning in the form of documentation from my personal perspective of learning. Cut the bullshit and turn it round.

The body of the

Higher-order functions

Higher-order functions are functions that use functions as arguments or return values.

I personally put this language feature in the first place because I felt it was something we didn’t support in the Java language. This feature, however, runs throughout the Kotlin language. So I put it in the first place, and I hope you can pay attention to this small feature. Take a look at a small demo to get a feel for this special feature:

// Function definition
fun funtion(num: Int, innerFun: (Int) -> Int) :Int {
    return innerFun(num)
}
Copy the code

A quick explanation of the above code. Let’s start with the function definition. Here we define a function called funtion that returns an Int. In addition, this function takes an Int argument and a parameter of function type (this function needs to pass an Int argument and returns an Int). Next we call:

// Function call
val result = funtion(1) {
	it + Awesome!
}
Copy the code

For Lambda, the input argument can be denoted by it if it is one

To be honest, the first time I saw this call, I was stunned. I wonder if my friend who just entered the pit felt the same as me? Because this notation contains a tip: our innerFun can be reduced to a Lambda, and we can write the Lambda outside of the function when the Lambda is the last argument. Funtion (1){} in the Demo.

One other thing to notice here is that our function instance doesn’t return because. The last expression in a lambda expression is the return value. These are essentially the two arguments that call the funtion method. Let’s write them in a more traditional way, they are equivalent:

val inner = fun(num: Int): Int {
	return num + 1
}
val result = funtion(1, inner)
Copy the code

OK, let’s strike while the iron is hot, and then feel the “SAO operation” of the function operation. Let’s take a look at this in practice:

// Function definition 1
fun funtion(num: Int, innerFun: (Int.Int) -> Int) :Int {
    return innerFun(num, num + 1)}// Function call 1 (as mentioned above, input parameter 1 can be used as it, but two or more? We can customize it as follows.
val result = funtion(1) { num1, num2 ->
    num1 + num2 + Awesome!
}
// Call 2 (we can also use anonymous functions, which are the same)
val result = funtion(1.fun(num1: Int, num2: Int): Int {
	return num1 + num2 + Awesome!
}
Copy the code

OK, so much for higher-order functions, because with this in fact, a lot of things are easy to learn. Let’s take a look at built-in encapsulation based on higher-order functions.

The operator

Set operator

Personally, the Kotlin operator. Collection operators are commonly used in development. For example, when we need to continuously transform some data, we might use RxJava.

Observable.create(new ObservableOnSubscribe<List<CustomModel>>() {
            @Override
            public void subscribe(ObservableEmitter<List<CustomModel>> e) throws Exception {
                // omit build List
      
                e.onNext(data);
            }
        }).flatMap(new Function<List<CustomModel>, ObservableSource<CustomModel>>() {
            @Override
            public ObservableSource<CustomModel> apply(List<CustomModel> customModels) throws Exception {
                return Observable.fromIterable(customModels);
            }
        }).map(new Function<CustomModel, String>() {
            @Override
            public String apply(CustomModel customModel) throws Exception {
                return customModel.name;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                / / s operation}});Copy the code

Here is a simple RxJava Demo: we have a List, first send it one by one, then convert each data to String, and finally to String processing. In Kotlin, what should we do to address these requirements? Thanks to operator support, we can easily do this type of operation:

val data = arrayListOf<CustomModel>(/ /... Omit the build process)
val newData=data.map {
    it.name
}.forEach {
    / / it operation
}
Copy the code

It’s very simple to use, and at first glance it looks very intimidating. But it’s very simple, remember the foundation of higher-order functions that we laid at the beginning. This is actually a call to data’s extension function map (an extension function is a syntax that extends an existing class). For example, this map extends Iterable, which we’ll expand on later). Cast it, and then call forEach to automatically traverse the collection.

Let’s click through and see the implementation:

// The map returns a List
      
       , which is the set of types that will be returned after the map. So we can keep making chain calls.
      
public inline fun <T, R>可迭代<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}
Copy the code

In plain English, the set operator here exposes the implementation of the transformation in the form of arguments and leaves it up to us to handle, and the rest is done by internal encapsulation. Of course, there are many interesting operators, you can go to understand. But the principles are much the same

Scope function

So we’re talking about operators that operate on sets. They’re just functions that extend on the corresponding set class. So some of you might ask, is there anything that works on the object? Yes, there is. That’s what we’re going to talk about next: scope functions.

It’s actually quite common:

"Kotlin".let{
	it.toInt()
}
"Kotlin".run{
	this.toInt()
}

"Kotlin".apply{
}
"Kotlin".also{
}

public inline fun <T, R> T.let(block: (T) -> R): R
public inline fun <T, R> T.run(block: T. () -> R): R

public inline fun <T> T.apply(block: T. () -> kotlin.Unit): T
public inline fun <T> T.also(block: (T) -> kotlin.Unit): T

Copy the code

Let’s see, the four of them are clearly defined. Here is the return value type, two categories:

  • Let/run. Either of these functions can return another type; The difference is that let has input arguments, while run does not.
  • Braking/apply. Both of these functions return their own values, with apply having no input and also having no input.

But even if you don’t have an input, you can use this to get itself.

The function above is quite convenient, for example:

Model model ;
/ /... Omit the initialization process
if(model! =null) {// omit large sections of operation logic
}
Copy the code

This way, in Kotlin, you can write:

model? .alse{// omit large sections of operation logic
}
// We can continue to call its scope function if necessary
Copy the code

If you have some else, you can’t do anything else, you can only do if-else in Kotlin

Of course, there are also some interesting scope functions, such as in Java:

boolean isTure;
// omit Boolean to determine logic
if(isTure){
	// omit large sections of operation logic
}
Copy the code

Kotlin can be done like this:

A certain object. TakeIf {// Boolean determines the logic}? . {// omit large sections of operation logic
}
// We can continue to call its scope function if necessary
Copy the code

TakeIf: Determines whether its (takeIf) return value is null or the caller based on the return value (true/false) of the function. If false, then null is returned, so use? To continue to call subsequent operations. I personally prefer scoped functions because you can omit a lot of ifs. Let’s switch to slightly more complicated logic: Given a method whose input parameter is a Model, we want to print the name of the Model object when its age property is greater than 10. For Java, we might write:

public void fun(Model model) {
	// Write three ifs.
    if(model ! =null) {
        if (model.age>10) {if(model.name! =null) {/ / print the model name}}}}class Model {
    String name;
    int age;
}
Copy the code

For Kotlin, we could write this:

fun funtion(model : Model){ model? .takeIf{ it.age >10}? .let{/ / print it. The name}}Copy the code

Isn’t that much simpler? But simplicity alone doesn’t seem to work… But to write it, it’s really cool! Do not believe, you can try ~~

The end of the

That’s all I want to talk about in this article. I think I actually understand higher-order functions. (PS: I don’t know why they are called higher-order functions. Kotlin can pick it up quickly and feel the cheerfulness of Kotlin’s writing. That’s because I didn’t accept new technology very well at the beginning, always thought there were all kinds of problems with new things… When I went to the headlines, I found that my colleagues were eager to learn (Kotlin? Nothing new to them… Jatpack, Flutter are already running on the online project) I have no reason to say: please don’t update, I can’t learn anymore… Or the same words: dry is done!

I am a fresh graduate, recently and friends maintain a public account, the content is that we in the transition from fresh graduate to the development of this way stepped on the pit, as well as our step by step learning records, if interested in friends can pay attention to it, together with fuel ~