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!