Here comes the squid game. Let’s go and see what level you get through.

See if your human compiler compiles the right results without the aid of an IDE.

Scala-like functions

fun hello() = {
    println("Hello, World")
}

hello()
Copy the code
  • a). Does not compile
  • B) Prints “Hello, World”
  • c). Nothing
  • d). Something else

Unused return value of a function with lambda expression body in ides, Lint will say Unused return value of a function with lambda expression body

Answer: C

To execute the lambda, use hello()(), or use hello().invoke()

This reminds me of the elegant operation in the Flutter: Immediately Invoked Function Expression (IIFE), that is (){}()

Indent trimming

val world = "multiline world"
println(
    """
        Hello
        \$world
    """.trimIndent()
)
Copy the code
  • a)
Hello
$world
Copy the code
  • b)
    Hello
    $world
Copy the code
  • c)
Hello
\multiline world
Copy the code
  • D) Doesn ‘t the compile

Answer: C

In Kotlin, raw tring is defined by a triple quote (“”) and does not contain escapes, but can contain newlines and any other characters. Even with the escape character \, string cannot be used there. If we have to show string we can’t use it there either. If we have to show string we can’t use it there either. If we must show string, we need to use {”} instead.

If-else chaining

fun printNumberSign(num: Int) {
    if (num < 0) {
        "negative"
    } else if (num > 0) {
        "positive"
    } else {
        "zero"
    }.let { Log.d("xys", it) }
}


printNumberSign(-2)
Log.d("xys", ",")
printNumberSign(0)
Log.d("xys", ",")
printNumberSign(2)
Copy the code
  • a) negative,zero,positive
  • b) negative,zero,
  • c) negative,,positive
  • d) ,zero,positive

Answer: D

,
zero
,
positive
Copy the code

Keep in mind that after the Java compiler processes the else if structure, it’s really just a “single-line “if calling else, that is, no matter how many else Ifs there are, it’s actually going to be converted to nesting in the else. In Kotlin, the function is parsed before the if-else block, so. Let {print(it)} applies only to the last else if. So in this case, the result of the first if statement will not be used and the function will return immediately. To avoid this, you can divide the entire if… else … Wrap it in little brackets, and then dot let on top of that.

Lambda runnables

fun run() { val run: () -> Unit = { println("Run run run!" Runnable {run()}.run()} call: run()Copy the code
  • A) “Run Run Run!”
  • B) Doesn ‘t the compile
  • c) StackOverflowError
  • d) None of the above

Answer: A,

This problem is actually examining the use of the Kotlin local function, and the above code is actually equivalent to the following code:

val run1: () -> Unit = { println("Run run run!" ) } fun run() { Runnable { run1() }.run() }Copy the code

With local functions, you can hide logic inside the function.

Making open abstract

open class A {
    open fun a() {}
}

abstract class B: A() {
    abstract override fun a()
}

open class C: B()
Copy the code
  • a) Compiles fine
  • B) Error: Class ‘C’ is not implement abstract base Class member
  • C) Error: ‘a’ overrides nothing
  • D) Error: Function ‘a’ must have a body

Answer: B

We could override an open function with an abstract function, but it would still be abstract. We would need to override the methods we want to implement in all subclasses, and code like the following would be executed.

open class A {
    open fun a() {}
}

abstract class B: A() {
    abstract override fun a()
}

open class C: B() {
    override fun a() {}
}

C().a()
Copy the code

List minus list

val list = listOf(1, 2, 3)
println(list - 1)
println(list - listOf(1))
val ones = listOf(1, 1, 1)
println(ones - 1)
println(ones - listOf(1))
Copy the code

Options:

a) [2, 3][2, 3][1, 1][1, 1]
b) [2, 3][2, 3][1, 1][]
c) [1, 3][2, 3][][1, 1]
d) [2, 3][2, 3][][]
Copy the code

Answer: B

This problem is actually examining the implementation of the minus function, in Kotlin:

  • List minus T: Removes the first matching element
  • List minus List: Removes all elements in the second List from the first List

Composition

operator fun (() -> Unit).plus(f: () -> Unit): () -> Unit = {
    this()
    f()
}

({ print("Hello, ") } + { print("World") })()
Copy the code
  • A) “Hello, World”
  • b) Error: Expecting top-level declaration
  • c) Error: Expression f cannot be invoked as a function
  • d) Error: Unresolved reference (operator + not defined for this types)
  • e) Works, but prints nothing

Answer: A,

The operator overload function plus is defined exactly right. It returns a new function (created using a lambda expression) that consists of two functions as arguments. When we add two functions, we have another function to call. When we call it, we have one lambda expression after another being called.

What am I?

val whatAmI = {}()
println(whatAmI)
Copy the code
  • A) “null”
  • B) “kotlin. Unit”
  • C) Doesn ‘t print anything
  • D) Doesn ‘t the compile

Answer: B

Lambda expressions do not return content, so their type is Unit.

Return return

fun f1(): Int {
    return return 42
}
fun f2() {
    throw throw Exception()
}
Copy the code

Can F1 and F2 be executed?

  • a) returns 42; throws exception
  • b) returns 42; Doesn ‘t the compile
  • C) doesn ‘t the compile; throws exception
  • D) doesn ‘t the compile; Doesn ‘t the compile

Answer: A,

The first return in F1 is actually invalid, if in an IDE, there will be a Lint prompt.

A return expression has a return type that can be used as an expression, and in F1, it also ends the execution of F1 with the result 42. Similarly, the throw declaration type — Nothing is also a return type, so both functions will compile, but will end up with an exception when f2 is called.

Extensions are resolved statically

Open class C class D: C() fun c.foo() = "C" fun d.foo () = "D" fun printFoo(C: C) {println(c.foo())} call: printFoo(D())Copy the code
  • A) Doesn ‘t the compile
  • b) Runtime error
  • c) c
  • d) d

Answer: C

This example looks at how the extension function is implemented. Because the called extension function depends only on the declared type of parameter C, that is, class C, it will only call the extension function foo of class C.

Extensions don’t actually modify the classes they extend. By defining an extension function, you are not actually inserting new members into a class, but simply allowing the new function to be called with a dot on a variable of that type, acting as a Wrapper.

Expression or not

fun f1() {
    var i = 0
    val j = i = 42
    println(j)
}

fun f2() {
    val f = fun() = 42
    println(f)
}

fun f3() {
    val c = class C
    println(c)
}
Copy the code

What are the results of F1, F2 and F3?

  • a)

    42 () -> kotlin.Int class C

  • b)

    42 () -> kotlin.Int doesn’t compile

  • c)

    Int doesn’t compile () -> kotlin.Int doesn’t compile

  • d)

    Doesn’t compile doesn’t compile doesn’t compile doesn’t compile

Answer: C

Variable initializers and class declarations are statements in Kotlin that do not declare any return types, so we cannot assign such declarations to variables and therefore do not compile. In F2 we actually implemented an anonymous function, so output a function.

Eager or lazy?

val x = listOf(1, 2, 3).filter {
    print("$it ")
    it >= 2
}

print("before sum ")
println(x.sum())
Copy the code
  • a) 1 2 3 before sum 5
  • b) 2 3 before sum 5
  • c) before sum 1 2 3 5
  • d) order is not deterministic

Answer: A,

Unlike the Stream API of Java8, the collection extension function in Kotlin is Eager. If you want to use Lazy, you can use sequenceOf or asSequence, which are lazily initialized.

Map default

val map = mapOf<Any, Any>().withDefault { "default" }
println(map["1"])
Copy the code
  • a) default
  • b) nothing
  • c) null
  • d) will not compile*

Answer: C

Don’t be fooled by the literal meaning of withDefault, which can only be used in delegate scenarios, so if you don’t know the extension function, be sure to look at the implementation, don’t guess.

val map = mutableMapOf<String, Set<String>>().withDefault { mutableSetOf() }

var property: Set<String> by map // returns empty set by default
Copy the code

Null empty

val s: String? = null if (s? .isEmpty()) println("is empty") if (s.isNullOrEmpty()) println("is null or empty")Copy the code
  • a) is empty is null or empty
  • b) is null or empty
  • c) prints nothing
  • D) doesn ‘t the compile

Answer: D

When s == null, s? .isempty () will return null, so the return type of this expression should be Boolean? , so, cannot compile. You can modify it in the following ways:

val s: String? = null if (s? .isEmpty() == true) { println("is empty") } if (s.isNullOrEmpty()) { println("is null or empty") }Copy the code

List or not

val x = listOf(1, 2, 3)
println(x is List<*>)
println(x is MutableList<*>)
println(x is java.util.List<*>)
Copy the code
  • a) true false true
  • b) false false true
  • c) true true true
  • d) true false false

Answer: C

In Kotlin, listOf, MutableList, and Java ArrayList all return java.util.List, so they are of the same type.

Everything is mutable

val readonly = listOf(1, 2, 3)

if (readonly is MutableList) {
    readonly.add(4)
}

println(readonly)
Copy the code
  • a) [1, 2, 3]
  • b) [1, 2, 3, 4]
  • c) UnsupportedOperationException
  • d) Will not compile

Answer: C

Arrays Helper functions like listOf and array.asList () return java.util.arraylis instead of java.util.arrayList, so they can’t be modified.

Fun with composition

val increment = { i: Int -> i + 1 } val bicrement = { i: Int -> i + 2 } val double = { i: Int -> i * 2 } val one = { 1 } private infix fun <T, R> (() -> T).then(another: (T) -> R): () -> R = { another(this()) } operator fun <T, R1, R2> ((T) -> R1).plus(another: (T) -> R2) = { x: T -> this(x) to another(x)} call: Val Return (x) = one then double then (increment + bicrement) println(return)Copy the code
  • A) Nothing, it doesn’t compile
  • b) 5
  • c) (1, 2)
  • d) (3, 4)

Answer: D

This is a classic compound function problem. The overloaded Plus function returns a pair generated by one or two functions, so we all start {1} with the then infix operator double, becoming 2. In Plus, 3 and 4 are executed, respectively.

Sorting

val list = arrayListOf(1, 5, 3, 2, 4)
val sortedList = list.sort()
println(sortedList)
Copy the code
  • a) [1, 5, 3, 2, 4]
  • b) [1, 2, 3, 4, 5]
  • c) kotlin.Unit
  • d) Will not compile

Answer: C

Sort: Kotlin sort: Kotlin sort: Kotlin sort

  • Sort () : Sorts a mutable collection, returning Unit
  • Sorted () : Returns the collection after sorting

So, just replace it with list.sorted().

Collection equality

println(listOf(1, 2, 3) == listOf(1, 2, 3))
println(listOf(1, 2, 3).asSequence() == listOf(1, 2, 3).asSequence())
println(sequenceOf(1, 2, 3) == sequenceOf(1, 2, 3))
Copy the code
  • a) true; true; true
  • b) true; true; false
  • c) true; false; true
  • d) true; false; false
  • e) false; false; false

Answer: D

The equality judgment of sets uses reference judgment, so two different lists cannot be equal, and sequence is also determined by reference address.

Good child has many names

open class C { open fun sum(x: Int = 1, y: Int = 2): Int = x + y } class D : C() { override fun sum(y: Int, x: Int): Int = super.sum(x, y)} val d: d = d () val c: c = d print(c.sum(x = 0)) print(", ") print(d.sum(x = 0))Copy the code
  • A) 2, 2
  • B) 1, 1
  • C) 2, 1
  • d) Will not compile

Answer: C

The main points of this question are the following:

  • Polymorphic, of a type determined at run time by the JVM virtual machine
  • Named functions are static and fixed at compile time

Overriding properties that are used in a parent

open class Parent(open val a: String) { init { println(a) } } class Children(override val a: String): Parent(a) call: Children(" ABC ")Copy the code
  • a) abc
  • b) Unresolved reference: a
  • C) Nothing, it won’t compile
  • d) null

Answer: D

This problem is one of the most troubling aspects of Kotlin implementing, so let’s examine the Java code Kotlin generates.

public static class Parent { private final String a; public String getA() { return this.a; } Parent(String a) { super(); this.a = a; System.out.print(this.getA()); } } public static final class Children extends Parent { private final String a; public String getA() { return this.a; } Children(String a) { super(a); this.a = a; }}Copy the code

As you can see, to get a we use getA method which references a. The only problem is that it is overriten in Child so it actually references a from Child which is not set yet at this point. It is because parent is always initialized first.

As you can see, the A in Parent is overwritten in Child, so it actually refers to the A in Child, which has not been set yet because the Parent class is always initialized first. So when using Kotlin’s simplified constructor, be careful about overwriting attributes.

Child apply

open class Node(val name: String) { fun lookup() = "lookup in: $name" } class Example : Node("container") { fun createChild(name: String): Node? = Node(name) val child1 = createChild("child1")? .apply { println("child1 ${lookup()}") } val child2 = createChild("child2").apply { println("child2 ${lookup()}") } } Call: Example ()Copy the code
  • A) child1 lookup in: child1; child2 lookup in: child2
  • B) child1 lookup in: child1; child2 lookup in: container
  • C) child1 lookup in: container; child2 lookup in: child2
  • D) none of the above

Answer: B

CreateChild returns nullable, so when child2 is applied, the context we receive is Node. . We cannot call lookup directly without unpack. If we want to do this, we should use this? The lookup (). Since we didn’t, the compiler searches for lookups it can use and finds its implementation in the Example context.

Negative numbers

print(-1.inc())
print(", ")
print(1 + -(1))
Copy the code
  • a) 0, 0
  • B) Won’t compile in line 4
  • c) 0, 2
  • d) -2, 0

Answer: D

In both cases, we use the unaryMinus operation on Int. When you type -1, it is the same as 1.unaryminus (). That’s why 1 plus minus (1) works correctly. -1. Inc () returns -2 because inc is used before the operator. This expression is equivalent to 1.inc().unaryminus (). To solve this problem, you should use the parentheses (-1).inc().

Copy

data class Container(val list: MutableList<String>)

val list = mutableListOf("one", "two")
val c1 = Container(list)
val c2 = c1.copy()
list += "oops"

println(c2.list.joinToString())
Copy the code
  • a) one, two
  • b) one, two, oops
  • c) UnsupportedOperationException
  • d) will not compile

Answer: B

The copy() method of the data class makes only a shallow copy, copying only references to fields. If you want to implement deep copy, you can avoid this problem by using immutable Data classes.

Covariance

class Wrapper<out T>

val instanceVariableOne : Wrapper<Nothing> = Wrapper<Any>()//Line A
val instanceVariableTwo : Wrapper<Any> = Wrapper<Nothing>()//Line B
Copy the code
  • a) Both lines A and B compile
  • b) Lines A and B do not compile
  • c) Line A compiles; Line B does not
  • d) Line B compiles; Line A does not

Answer: D

Wrapper is a subtype of Wrapper because Nothing is a subtype of Any. The Wrapper subtype is the same as the T subtype. Row B is good. Line A does not compile. It assigns a supertype to a subtype.

Receivers wars

fun foo() { println("Top-level rule") } class Foo { fun foo() { println("Extension receiver rule") } } class Test { fun foo() { println("Dispatch receiver rule") } fun Foo.foo() { println("Member extension function rule") } fun Foo.test() { Foo()} fun testFoo() {foo().test()}} call: test().testfoo ()Copy the code
  • a) Top-level rule
  • b) Extension receiver rule
  • c) Dispatch receiver rule
  • d) Member extension function rule

Answer: B

When we have an extension receiver (Foo), its methods always have higher priority than the Dispatch receiver (methods in the same class).

The Extension Receiver must be called when the Member Extension and extension Receiver conflict, so the Member Extension has the lowest priority.

Int plus-plus

var i = 0
println(i.inc())
println(i.inc())

var j = 0
println(j++)
println(++j)
Copy the code
  • a) 0, 1, 0, 1
  • b) 0, 1, 0, 2
  • c) 1, 1, 0, 2
  • d) 1, 2, 0, 1

Answer: C

This problem has existed since C++, again recalling tan haoqiang’s domination. The prefix operator ++ (++j) increments the number and returns the new value, and the suffix operator also increments the attribute but returns the previous value.

The confusing part is that both the prefix and suffix are references to the Kotlin function inc. If you click ++ I and I ++ from the IDE, you jump to the reference to inc, which returns a new value but is not assigned.

Return in function literal

fun f1() { (1.. 4).forEach { if (it == 2) return println(it) } } fun f2() { (1.. ForEach (fun(it) {if (it == 2) return println(it)})} call: f1() f2()Copy the code
  • a) 134134
  • b) 1134
  • c) 1341
  • D) Doesn ‘t the compile

Answer: B

When we want to use a return in a lambda expression, we need to use a tag like return@forEach, otherwise it jumps out of the entire lambda.

Since for-each is inline, f2 actually uses an anonymous function, where return exits the function instead of the lambda.

WTF with labels

val j = wtf@ { n: Int -> wtf@ (wtf@ n + wtf@ 2) }(10)
println(j)
Copy the code
  • A) It won ‘t the compile
  • b) 10
  • c) 2
  • d) 12

Answer: D

Labels don’t work here. Don’t let him fool you.

Order of nullable operators

val x: Int? = 2 val y: Int = 3 val sum = x? :0 + y println(sum)Copy the code
  • a) 3
  • b) 5
  • c) 2
  • d) 0

Answer: C

Elvis operator has a lower priority than +, so the plus sign is executed first, which becomes x? :3, the answer is 2, and the priority can be changed by parentheses (x3:0).

Extended enums

enum class Color { Red, Green, Blue } fun Color.from(s: String) = when (s) {"#FF0000" -> color.red "#00FF00" -> color.green "#0000FF" -> color.blue else -> null}  println(Color.from("#00FF00"))Copy the code
  • a) Green
  • b) Color.Green
  • c) null
  • d) will not compile

Answer: D

Extensions to Color only apply to instances of Color, for example, color.blue.from (), and extensions to the enumeration itself can only be done if it has a Companion object.

enum class Color {
  Red, Green, Blue;
  companion object 
}

fun Color.Companion.from(...)
Copy the code

This is another dirty operation.

Hello blocks

Fun Hello (block: String.() -> Unit) {"Hello1". Block () block("Hello2")} call: hello {println(this)}Copy the code
  • a) Hello1
  • b) Hello2
  • c) Hello1Hello2
  • d) will not compile

Answer: C

The point of this problem is to figure out which is a lambda and which is an extended function with a receiver.

I am this

Data class IAm(var foo: String) {fun hello() = foo.apply {return this}} call: println(IAm("bar").hello())Copy the code
  • a) IAm
  • b) IAm(foo=bar)
  • c) bar
  • d) Will not compile

Answer: C

Don’t be fooled, this is a piece of junk code.

Overextension

operator fun String.invoke(x: () -> String) = this + x() fun String.z() = "! $this" fun String.toString() = "$this!" Call: println (" x "{" y"}. Z ())Copy the code
  • a) ! x
  • b) ! xy
  • c) ! xy!
  • d) Will not compile

Answer: B

(x) {“y”}.z() = invoke (x) {“y”}.z() = invoke (x) {“y”}.z() = invoke (x) {“y”}.

This is another operation that can perform other initialization operations while the object is being initialized.

Lazy delegate

class Lazy { var x = 0 val y by lazy { 1 / x } fun hello() { try { print(y) } catch (e: Exception) {x = 1 print(y)}}} Lazy().hello()Copy the code
  • a) 0
  • b) 1
  • c) NaN
  • d) ArithmeticException

Answer: B

The Lazy delegate can be called multiple times until it actually returns a value, so after an exception is thrown, the value of x is changed and y can be assigned, thus printing out.

Sneaky return

fun numbers(list: List<Int>) {List. ForEach {if (it > 2) return println(it)} println("ok")} call: numbers(listOf(1, 2, 3))Copy the code
  • a) 123ok
  • b) 12ok
  • c) 12
  • d) Infinite loop

Answer: C

The return in lambda will return directly from the function, so the function breaks.

Two lambdas

typealias L = (String) -> Unit fun foo(one: L = {}, two: L = {} {one (" one "), two (" two ")} call: foo {println (it)} foo ({println (it)})Copy the code
  • a) oneone
  • b) twotwo
  • c) onetwo
  • d) none of the above
  • e) none of the above (twoone)

Answer: E

Foo {} is actually the last argument to foo, and foo(), what’s in parentheses, is actually the first argument in foo, in order.

  • This is great for DSLS, and Kotlin allows you to write all kinds of DSLS
  • But it can be confusing when combined with default arguments, don’t take many lambdas as arguments, and avoid using defaults if you still do

The case comes from Puzzlers on Kt. Academy

awards

-Blair: The var reward? = nullCopy the code

A lot of people say, what’s the use of these things, a lot of code in the IDE can know what’s right, what’s wrong, what’s the result, why do it?

In fact, to understand these things, for your programming thinking will be of great help and understanding of language ability, inside the IDE, it help us to do too many things, so many times we all can’t truly see what is the nature of the problems, with the help of these subjects of training, we can understand how processing code, the compiler can understand the code is how to perform, That’s what we train them for.

So, did you survive the squid game to the end?

I would like to recommend my website xuyisheng. Top/focusing on Android-Kotlin-flutter welcome you to visit