The function of Kotlin learning

Source: Internet
Author: User

function declaration

Declare the function with the keyword fun in Kotlin:

fun double(x:Int):Int{}

where int is the return value type, x indicates that the parameter type is int

function usage

To call a function through a traditional method:

 val result=double(2)

You can pass the . Call member function
Sample (). Foo ()
Sample () is an instance of the sample class

Infix symbol

The function is called by infix notation when the following conditions are met:

    • function as member function or extension function
    • function has only one parameter
    • function tagged with infix keyword

      //Int的扩展函数infix fun Int.shl(x:Int):Int{...}//调用扩展函数可以用中缀表示法1 sh1 2//或者 1.she(2)
Parameters

The parameters of the function are defined using the Pascal command method, in the form: Name:type. The parameters are separated by commas, and each parameter must indicate the type.

fun powerOf(number:Int,exponent:Int){...}
Default parameters

The parameters of the function can have a default value, and the default value is used when the corresponding parameter is ignored.
The number of overloads is less than in other languages.

fun read(b:Array<Byte>,off:Int=0,len;Int=b.size()){...}

The default value is defined after the corresponding type.

Command parameters

The method parameter can be named when the function is called, which is convenient when the function has many parameters or has a default value.

fun reformat(str : String,normailizeCase :Boolean=true,upperCaseFirstLetter: Boolean = true,divideByCamelHumps: Boolean = false,wordSeparator: Char = ‘ ‘){...}

I can call methods with default values:

reformat(str)

When we call a non-default it's like this:

reformat(str,true,true,false,‘_‘)

Use command parameters to improve readability

    reformat(str,normalizeCase=true,upperCaseFirstLetter = true,divideByCamelHumps = false,wordSeparator = ‘_‘)

If we don't need all the parameters

reformat(str,wordSeparator=‘_‘)

You cannot use named parameter syntax when calling Java functions, because Java bytecode does not ensure that the method parameter names are invariant.

Single representation

When a function uses a single notation, the curly braces can be omitted, and the function body is defined at the back of =

fun double(x:Int):Int=x*2

Specifying the return type is optional when the return type can be inferred by the compiler.

fun double(x:Int)=x*2
Explicitly specifying the return type

When a function has a block of code, it must explicitly indicate the return type, which is not explicitly specified if it is returned to the unit. Kotlin cannot infer the return type when the function has a block of code, because there is a complex flow of control in the code, and the return type is not intuitive to the reader.

Non-quantitative parameters (Varargs)

The parameters of the function can be vararg to indicate the variable number of arguments

fun <T>asList(vararg ts:T):List<T>{ val result=ArrayList<T>() for(t in ts) result.add(t) return result }

You can call this:

val list=asList(1,2,3)

Inside the function T is equivalent to an array, in this case the TS variable is a reference to the Array<out t>

Only one parameter can be marked with vararg, and if the last parameter is not vararg, we will assign it with the named parameter method. Or, if the argument is a function type, you can pass a lambda expression.

When we call a vararg function, we can pass it one at a time, like aslist, or I already have a ready-made array to pass it to the function, and we can use the * prefix to refer to the

val a=arrayOf(1,2,3)val list=asList(-1,0,*a,4)
function scope

Functions can be defined as top-level functions in Kotlin, meaning you don't have to define a class like Java,c#,scala to define a function as a member function. In addition to the top-level functions, Kotlin's function types also include local functions, such as member functions and extension functions.

Local functions

Kotlin supports local functions: functions inside other functions.

fun dfs(graph: Graph) {fun dfs(current: Vertex, visited: Set<Vertex>) {if (!visited.add(current)) returnfor (v in current.neighbors)dfs(v, visited)}dfs(graph.vertices[0], HashSet())}

A local function can access local variables of local external functions, so in the example above, visited can be set to local variables.

fun dfs(graph: Graph) {val visited = HashSet<Vertex>()fun dfs(current: Vertex) {if (!visited.add(current)) returnfor (v in current.neighbors)dfs(v)}dfs(graph.vertices[0])}
member functions

A member function is a function that is defined within a class or object.

class Sample(){fun foo(){print("Foo")}}

member functions are called with a. Symbol

Sample().foo()
Generic functions

A function that uses <> to specify a generic parameter before the name of the function is called a generic function.

fun <T> singletonList(item:T):List<T>{//...}

If you want to learn more about generic functions, look at the generics of Kotlin-

Tail recursive function

Kotlin is a support for tail recursive functions, which allows some algorithms to use loops instead of writing a recursive function without the risk of memory overflow. If a function is marked with the Tailrec modifier, it satisfies the condition of the compiler to optimize recursion and replaces it with an efficient and fast loop.

    tailrec fun findFixPoint(x: Double = 1.0): Double    = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

This code calculates the mathematical cosine of the fixed point. Math.Cos is repeated from 1.0 until the value is unchanged, and the result is 0.7390851332151607 this code is equivalent to the following:

private fun findFixPoint(): Double {var x = 1.0while (true) {    val y = Math.cos(x)    if ( x == y ) return y    x = y    }}

You must call yourself in the last operation using the Tailrec modifier. No other code is allowed after the recursive calling code, and it cannot be used in a try/catch/finall block. The current tail recursion is only available in the back end of the JVM

Higher-order functions and lambda expressions

Higher-order functions are functions that can accept functions as arguments or return a function. For example, lock () is a good example of receiving a lock object and a function, running the function and releasing the lock

fun lock<T>(lock: Lock, body: () -> T ) : T {lock.lock()try {    return body()}finally {    lock.unlock()}}

Now explain the code above: the body has a function type (), T, which is conceived as a function that has no parameters and returns the type T. It throws an internal try function block and is protected by lock, and the result is returned by the lock () function.
If we want to call lock (), the function, we can pass it to another function to do the argument, see the function Reference:

fun toBeSynchronized() = sharedResource.operation()val result = lock(lock, ::toBeSynchronized)

In fact, the most convenient way is to pass a literal function (usually a lambda expression):

    val result = lock(lock, { sharedResource.operation() })

The literal function often describes more details, but to continue this section, let's look at a simpler preview:

    • The literal function is wrapped in curly braces.
    • Arguments are declared earlier (parameter types can be omitted)
    • function Body After

There is a convention in Kotlin that if the last argument is a function, it can be defined outside the parentheses:

lock (lock) {sharedResource.operation()}

Another example of a higher order function is map () (of MapReduce):

    fun <T, R> List<T>.map(transform: (T) -> R): List<R> {val result = arrayListOf<R>()for (item in this)result.add(transform(item))return result}

This can be called:

val doubled = ints.map { it -> it * 2 }

Parentheses can be completely ignored when the parameter has only one function.
If the literal function has only one argument, the declaration can be omitted, and the name is it:

ints map {it * 2}

This allows you to write linq--style code:

strings filter {it.length == 5} sortBy {it} map {it.toUpperCase()}
inline functions

Using higher-order functions brings about the corresponding run-time trouble: Each function is an object that captures closures, meaning that these variables can be accessed within the function body. The allocation of memory, the operation of virtual calls will bring overhead.
But in most of this overhead can be avoided by inline text functions. Here's a good example. The lock () function can be easily inline when invoked. Consider the following example:

lock(l){foo()}

Instead of creating a function with parameters and generating a call, the heart compiler compiles the following code:

l.lock()try {foo()}finally {l.unlock()}

This is not the first we want??
In order for the compiler to do this, we need to mark lock with the inline modifier ()

    inline fun lock<T>(lock: Lock, body: () -> T): T {// ...}

The Lnline modifier affects both the function itself and the incoming lambda: they all inline at the time of the call.
The federation allows the generated code to increase, but if we can reasonably solve it (do not inline a large function), there will be a lot of performance loss.

@noinline

In order for you to want some lambda expressions to be passed inline to the inline function, you can tag some of your function parameters @noinline annotations:

    inline fun foo(inlined: () -> Uint, @noinline notInlined: () -> Unit) {//...}

Inline lambda can only be called in inline functions, or as inline parameters, but @noinline tags can be manipulated in any way we like: stored in fields, (transitive, etc.)
Note If the inline function does not have an inline function parameter and there is no specific type of argument, the compiler will report a warning so that the inline function has no merit (if you think inline is necessary you can ignore the warning)

Non-local return

In Kotlin, we can use return without conditions to exit a named function or an expression function. This means that this exits a lambda function, we have to use the label, and the Blank return is forbidden in the lambda function because the lambda function cannot create a closed function to return:

fun foo() {ordinaryFunction {    return // 错误 不可以在这返回}}

However, if the lambda function is passed inline, the return is also inline, so allow the following:

fun foo() {inlineFunction {    return //}}

Note that some inline functions can invoke a lambda function that is passed in, but not in the body of the function, but in the context of another execution, such as a local object or a nested function. In such a case, the non-local control flow is also not allowed in the lambda function. To show that the lambda parameter needs to have Inlineoptions.only_local_return annotations:

        inline fun f(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) body: () -> Unit) {    val f = object: Runnable {    override fun run() = body()}    // ...}

Inline lambda is not allowed with break or continue, but may be supported later in the release.

Instantiating parameter types

Sometimes we need to access the passed-over type as a parameter:

    fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {var p = parentwhile (p != null && !clazz.isInstance(p)) {    p = p?.parent}@suppress("UNCHECKED_CAST")return p as T}

Now we have created a tree and used reflection to check whether it is a particular type. Everything looks good, but the point of call is tedious:

myTree.findParentOfType(javaClass<MyTreeNodeType>() )

All we want is to pass a type to this function, which is like this:

myTree.findParentOfType<MyTreeNodeType>()

To achieve this, inline functions support materialized type parameters, so we can write this:

inline fun &lt;reified T> TreeNode.findParentOfType(): T? {var p = parentwhile (p != null && p !is T) {    p = p?.parent}return p as T}

We use the refied modifier to check the type parameter, since it can be accessed inside the function, and it is basically close to the normal function. Because functions are inline, they are not allowed to be reflected, and operations such as!is ' as ' can be used. At the same time, we can call it as above.

myTree.findParentOfType&lt;MyTreeNodeType>()

Although reflection is used in many cases, we can still use the instantiated type parameter Javaclass () to access it:

inline fun methodsOf&lt;reified T>() = javaClass&lt;T>().getMethods()fun main(s: Array&lt;String>) {println(methodsOf&lt;String>().joinToString(‘\n‘))}

An ordinary function (not marked inline) cannot have an instantiated parameter.

anonymous functions and function expressions

An anonymous function is a function that is not declared, but is immediately passed down as an expression. Take a look at the following example:

max(strings, { a, b -> a.length() < b.length() })

The Max function is a high-order function that takes a function as the second argument. The second argument is an expression, so this is a function, that is, a literal function. As a function, it is equivalent to:

fun compare(a: String, b: String) : Boolean = a.length < b.length
function type

One function takes another function as an argument, and we have to specify a type for it. For example, the above definition of Max is this:

fun max<T>(collection: Collection<out T>, less: (T, T) -> Boolean): T? {var max: T? = nullfor (it in collection)    if (max == null || less(max!!, it))        max = itreturn max}

The parameter less is a Boolean type (T, T), which means that two T-type arguments are accepted to return a Boolean: True if the first argument is smaller than the second one.
In the function body line fourth, less is used as a function
A function type can be written like the above, or it can have named parameters, more see named parameters

val compare: (x: T,y: T) -> Int = ...
Lambda expression syntax

The full wording of the lambda expression is the following:

val sum = { x: Int, y: Int -> x + y }

The lambda expression is wrapped in curly braces, the type annotation is optional, and the function body is after, like this:

val sum: (Int, Int) -> Int = {x, y -> x+y }

function text sometimes has only one parameter. If Kotlin can compute the signature from its native, this unique argument can be omitted, and it is implicitly declared by it:

ints.filter {it > 0}//这是 (it: Int) -> Boolean  的字面意思
anonymous functions

In the case of lambda: in a function expression, you can specify the return type of the function. In most cases it is not necessary to specify because the return type can be automatically recognized, but when you use anonymous functions you must specify:

fun (x:Int,y:Int):Int=x+y

An anonymous data and regular function looks very much like, except that the name is omitted. Its function body can be an expression or a block of code:

fun(x:Int,y:Int):Int{return x+y}

Its parameters and return type definitions are the same as regular functions, except that the parameter is ignored and this parameter can be inferred from the context environment:

ints.filter(fun(item)=item>0)

The inference of the anonymous function return type is the same as the normal function:
The return type can be inferred when the anonymous function has only one expression and when the anonymous function has a block of code, it must specify his return type.
Note: Usually the parameters of an anonymous function are passed in from outside, and this abbreviation allows only arguments outside the function bracket to work in a lambda expression

Another place where an anonymous function differs from a lambda expression is when handling a non-local return value. A non-tagged return expression is usually returned from a function that does not have the FUN keyword when the function is declared. This means that the return value of the lambda expression is returned from the enclosing function, and the anonymous function returns from the anonymous function itself.

Closed Package

A lambda expression or an anonymous function (as well as local functions and object expressions) can access closures, such as defining variables outside the scope of the action. Unlike Java, capturing variables in closures can be modified:

var sum = 0ints.filter { it > 0 }.forEach {sum += it}print(sum)
receive function literal

Kotlin supports invoking functions with the specified recipient object. Inside the function literal, you can invoke the function with an object that has no additional modifiers. You can intelligently extend functions that allow you to invoke the members of a recipient object inside a function.

 sum:Int.(other:Int)->Int

If it is the receiver's method, this function literal can be called:

1.sum(2)

Anonymous functions can directly specify the recipient type of the function literal. If you define a variable of a function type that has a receiver, you can use it later:

    var sum=fun Int.(other:Int)=this+other

When the recipient type can be inferred from the context, the lambda expression can be used as a function literal with a receiver.

The function of Kotlin learning

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.