kotlin核心编程

If you are new to Kotlin please check out my previous post on Kotlin Guide for Beginners first before moving forward for better understanding. In this post let’s check some basics and a few interesting things about functions in Kotlin.

如果您是Kotlin的新手,请先阅读我以前在Kotlin入门指南中的文章,然后再继续进行进一步的了解。 在这篇文章中,让我们检查一下Kotlin函数的一些基础知识和一些有趣的事情。

如何在Kotlin中编写函数或方法? (How to write functions or methods in Kotlin?)

A function is nothing but a collection of statements. A function needs to be called explicitly to execute that block of statements. To maintain readability and ease of understanding, we write n number of functions in our classes. Methods are used to perform certain actions.

函数不过是语句的集合。 需要显式调用一个函数以执行该语句块。 为了保持可读性和易于理解性,我们在类中编写了n个函数。 方法用于执行某些动作。

A function must be declared within a class. To declare a method in Kotlin we mainly need three different parameters

函数必须在类中声明。 要在Kotlin中声明方法,我们主要需要三个不同的参数

  • fun — In Kotlin functions are declared with the fun keyword

    fun —在Kotlin中,函数使用fun关键字声明

  • name — We need to have a unique name for each method

    名称 -每个方法都需要有一个唯一的 名称

  • ()parenthesis which common for method declarations across most of the programming languages

    ()括号 ,在大多数编程语言中通常用于方法声明

fun doSomeThing() {
        print("Welcome to Kotlin")
    }

The above is a simple function that prints “Welcome to Kotlin” when executed.

上面是一个简单的函数,在执行时会显示“ Welcome to Kotlin”。

示例说明 (Example Explained)

  • doSomeThing() is the name of the method

    doSomeThing()是方法的名称

  • {} — is the method block defining the start and end of the method

    {} —是定义方法开始和结束的方法块

Apart from this, we need to know some more things related to methods.

除此之外,我们还需要了解与方法有关的更多信息。

参数或参数 (Parameters or Arguments)

If we want to pass some information to methods we can send it as a parameter. They act as local variables inside the method block. Parameters are specified inside the parentheses() of the method. We can add as many parameters as we want, by just separating them with a comma.

如果我们想将一些信息传递给方法,我们可以将其作为参数发送。 它们充当方法块内的局部变量。 参数在方法的括号()中指定。 我们可以添加任意数量的参数,只需用逗号分隔即可。

The example of a parameterized function is as following

参数化函数的示例如下

Image for post

返回类型 (Return Type)

A return type specifies whether a method or function wants to return something or not. In Kotlin language, if a method wants to return something we need to specify the return type of function and return value of the method along with return keyword(optional). Have a look at the following snippet

返回类型指定方法或函数是否要返回某些内容。 在Kotlin语言中,如果方法要返回某些内容,则需要指定函数的返回类型和方法的返回值以及return关键字(可选)。 看看以下片段

Image for post

Here it’s a simple use case of adding two numbers and returning the result. But in real case scenario imagine where we have a URL and want to get the image file downloaded so here we write a method passing URL as an argument to that method like say dowloadImage(url:String) and inside the method, we write all the stuff of downloading the image and finally return the image file.

这是添加两个数字并返回结果的简单用例。 但是在实际情况下,假设我们有一个URL并想下载图像文件,因此在这里我们编写一个将URL作为该方法的参数传递的方法,例如dowloadImage(url:String),并在该方法内部编写所有下载图片并最终返回图片文件。

As Kotlin is a user-friendly language we can write the same add method in different ways but the result is the same

由于Kotlin是一种用户友好的语言,因此我们可以用不同的方式编写相同的add方法,但结果是相同的

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


fun add(a: Int, b: Int) = a + b


fun add(a: Int, b: Int): Int = a + b

This is all about the basics of writings function in Kotlin. Now let’s learn some advanced concepts supported in Kotlin.

这一切都是关于Kotlin写作功能的基础。 现在让我们学习Kotlin支持的一些高级概念。

与Kotlin中的功能相关的高级概念 (Advanced concepts related to functions in Kotlin)

默认参数 (Default Arguments)

In Kotlin we have an option of default arguments in function declarations. It means function arguments can have default values, which were used when a corresponding argument is omitted from the function call. It was not supported in Java. This allows for a reduced number of overloads compared to other programming languages.

在Kotlin中,我们可以在函数声明中选择默认参数。 这意味着函数自变量可以具有默认值,该默认值是在函数调用中省略相应自变量时使用的。 Java不支持它。 与其他编程语言相比,这可以减少数量的重载。

fun foo(i: Int = 10){
print(i)
}

so if we call foo() anywhere it gets executed and prints the default value and if we provide any values then the default value will be overridden with the value provided during the method call.

因此,如果我们在执行的任何地方调用foo()并打印默认值,并且如果我们提供任何值,则默认值将被方法调用期间提供的值覆盖。

命名参数 (Named arguments)

Function parameters can be named while calling the functions. It is a very convenient way when a function has a more number of parameters or variable default arguments. While method calls we can use that name to provide the value. Let’s take a look at a function

可以在调用函数时命名函数参数。 当函数具有更多参数或可变默认参数时,这是一种非常方便的方法。 在方法调用中,我们可以使用该名称来提供值。 让我们看一个函数

fun printMyDetails(str: String,
             isValid: Boolean = true,
             isUpperCase: Boolean = true,
             firstLetter: Char = ' ') {
......
}

We can call this using default argument:

我们可以使用默认参数来调用它:

printMyDetails(str)

else we can pass all the arguments to override the default values

否则我们可以传递所有参数以覆盖默认值

printMyDetails(str, true, true, false, 's')

but here in the above method call, we may get confused which boolean value specified to which arguments. So here is how we can use named arguments

但是在上面的方法调用中,我们可能会混淆将哪个布尔值指定给哪些参数。 所以这是我们如何使用命名参数的方法

printMyDetails(str,
    isValid = true,
    isUpperCase = true,
    firstLetter = 'a'
)

This is how it would be much clear and easily understandable.

这将是非常清晰和易于理解的方式。

Kotlin扩展 (Kotlin Extensions)

Extensions are one of the widely used concepts from Kotlin's selection.

扩展是Kotlin选择的广泛使用的概念之一。

As per Kotlin’s documentation :

根据Kotlin的文档

“Kotlin provides the ability to extend a class with new functionality without having to inherit from the class or use design patterns such as Decorator. This is done via special declarations called extensions.”

“ Kotlin提供了使用新功能扩展类的能力,而不必从类中继承或使用诸如Decorator之类的设计模式。 这是通过称为扩展名的特殊声明来完成的。”

It means without inheriting a class we can extend or customize its functionality. When we are using a third-party library we can simply write new functions for a class without modifying the actual class. This mechanism is called extension functions.

这意味着无需继承类,我们就可以扩展或自定义其功能。 当我们使用第三方库时,我们可以简单地为一个类编写新函数,而无需修改实际的类。 这种机制称为扩展功能

This was actually a very interesting feature so now it has become a common thing like most people are using it everywhere for customization and to reduce boilerplate code.

这实际上是一个非常有趣的功能,所以现在它已成为一种常识,就像大多数人在各处使用它进行自定义和减少样板代码一样。

Let’s check a basic example of showing a toast message inside an activity.

我们来看一个在活动中显示敬酒消息的基本示例。

To show a toast message we generally write one common sentence like

为了显示吐司消息,我们通常写一个普通的句子,例如

Toast.makeText(this, "message", Toast.LENGTH_SHORT).show()

And generally, it’s a common practice of showing toast messages at multiple activities and repeating the same line at multiple points and unnecessary imports of Toast class everywhere.

通常,这是一种常见的做法,即在多个活动中显示Toast消息,并在多个点重复同一行,并在所有地方不必要地导入Toast类。

So to reduce this we can create a toast extension function and call it everywhere. We can create an extension function over Activity or Fragment or simply on Context. Let’s check with Context

因此,为减少这种情况,我们可以创建一个Toast扩展函数,并在任何地方调用它。 我们可以在Activity或Fragment或仅在Context上创建扩展功能。 让我们检查上下文

fun Context.toast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, duration).show()
}

And we can call this from any activity by passing a message to show like

我们可以通过传递一条消息来显示任何内容

toast(getString(R.string.something_wentwrong))

Following are the list of Context-based extension function that I use in my projects to remove boilerplate code and increase productivity

以下是我在项目中使用的基于上下文的扩展功能列表,该功能可删除样板代码并提高生产率

package com.example.utils.extensions


import android.content.Context
import android.util.TypedValue
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat




@ColorInt
fun Context.getColorCompat(@ColorRes resourceId: Int) = ContextCompat.getColor(this, resourceId)


fun Context.getDrawableCompat(@DrawableRes resId: Int) = ContextCompat.getDrawable(this, resId)


fun Context.getDimension(@DimenRes resourceId: Int) = resources.getDimension(resourceId)


val Context.screenWidth: Int
    get() = resources.displayMetrics.widthPixels


val Context.screenHeight: Int
    get() = resources.displayMetrics.heightPixels


fun Context.toast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, msg, duration).show()
}


fun Context.getPxFromDp(dp: Float) = TypedValue
    .applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).toInt()

“Extensions are resolved statically which means the extension function being called is determined by the type of the expression on which the function is invoked, not by the type of the result of evaluating that expression at runtime” — from Kotlin docs

“扩展是静态解析的,这意味着被调用的扩展函数是由调用该函数的表达式类型决定的,而不是由运行时对该表达式求值的结果类型决定的” –来自Kotlin docs

Kotlin提供的默认扩展名 (Default Extension provided by Kotlin)

There are also some predefined or default Kotlin extensions that we can make use of. Let’s check few default extensions on collections like filter, firstOrNull

我们还可以使用一些预定义或默认的Kotlin扩展。 让我们检查一下集合中的一些默认扩展,例如filterfirstOrNull

filter — Returns a list containing only elements matching the given condition or predicate.

filter —返回仅包含与给定条件或谓词匹配的元素的列表。

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

Isn’t that good? In Java, we use to write all the loops, iterate and get things done.

这样不好吗 在Java中,我们用来编写所有循环,进行迭代并完成工作。

FirstOrNull — returns the first element, or a `null` if the collection is empty.

FirstOrNull —返回第一个元素,如果集合为空,则返回null。

public fun <T> Iterable<T>.firstOrNull(): T? {
    when (this) {
        is List -> {
            if (isEmpty())
                return null
            else
                return this[0]
        }
        else -> {
            val iterator = iterator()
            if (!iterator.hasNext())
                return null
            return iterator.next()
        }
    }
}

You will get to know more about these and how useful are they while using them. So try them out.

您将了解有关它们的更多信息,以及它们在使用时的实用性。 因此,请尝试一下。

高阶函数 (High Order Functions)

A function that can take a function as a parameter or has a return type of function is called higher-order functions. Either of conditions must be met

可以将函数作为参数或具有函数返回类型的函数称为高阶函数。 必须满足任何条件

  • it accepts a function as a parameter

    它接受一个函数作为参数
  • it returns a function

    它返回一个函数

Take a look at the simple snippet

看看简单的代码片段

fun multiply(a: Int, b: Int): Int {
    return a * b
}


fun returnMultiplyFunction(): ((Int, Int) -> Int) {
    return ::multiply
}

The most common usage is handling of Recyclerview adapter click. On the click of an item in an adapter, we need to pass some data back so here we would handle that efficiently.

最常见的用法是处理Recyclerview适配器单击。 单击适配器中的某个项目后,我们需要将一些数据传回,因此在这里我们将有效地处理该数据。

Inside the activity or fragment while defining the adapter we need to pass a method where on the click of an item inside adapter we just invoke the block inside the adapter so the code in the respective fragment or activity gets executed.

在定义适配器的活动或片段内部,我们需要传递一个方法,在单击适配器内部的项目时,我们只需调用适配器内部的块,以便执行相应片段或活动中的代码。

The following is the snippet to pass function from activity to adapter

以下是将功能从活动传递到适配器的代码片段

private val sideNavAdapter: SideNavAdapter = SideNavAdapter {position, item ->
        onItemClick(position,item)
    }


    private fun onItemClick(position: Int, item: SideNavItem) {
     //Custom Handling of item depending on our requirements 
      .....
    }

The following is the snippet of invoking the passed function with required args inside the adapter

以下是在适配器内部使用必需的arg调用传递的函数的代码段

class SideNavAdapter(private val onItemClick: ((position: Int, item: SideNavItem) -> Unit)) :
    RecyclerView.Adapter<SideNavAdapter.SideNavVH>() {
 
    var menuItemsList = ArrayList<SideNavItem>()


    inner class SideNavVH(inflate: View) : RecyclerView.ViewHolder(inflate) {
        var sideNavItem : SideNavItem?=null
        init {
            itemView.setOnClickListener {
                sideNavItem.let {
                    onItemClick.invoke(adapterPosition, sideNavItem)
                }
            }
        }
        fun setData(sideNavItem: SideNavItem) {
            this.sideNavItem = sideNavItem
            itemView.iv_nav?.setImageResource(sideNavItem.resourceId)
            itemView.tv_nav_name?.text = sideNavItem.itemName
        }
    }
    ......
}

摘要 (Summary)

By now you should have a basic idea of how do we use functions in Kotlin. Please stay tuned I will keep writing more posts on Kotlin language series.

到目前为止,您应该对如何在Kotlin中使用函数有基本的了解。 请保持关注,我将继续写更多有关Kotlin语言系列的文章。

Continue reading on Kotlin:

继续阅读Kotlin:

Please let me know your suggestions and comments.

请让我知道您的建议和意见。

You can find me on Medium and LinkedIn

您可以在MediumLinkedIn上找到我…

Thanks for reading…

谢谢阅读…

翻译自: https://medium.com/android-dev-hacks/kotlin-advanced-programming-89aef9b2ecb8

kotlin核心编程

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐