Here comes the squid game. Now let's start. Let's see what level you've passed.
Without the aid of IDE, see whether your human flesh compiler can compile the correct results.
Scala-like functions
fun hello() = { println("Hello, World") } hello()
a). Does not compile
b). Prints "Hello, World"
c). Nothing
d). Something else
Tip: in the IDE, lint will prompt, Unused return value of a function with lambda expression body
Answer: C
To execute this lambda, you need to use hello()(), or hello () invoke()
This reminds me of an operation in fluent: immediately invoked function expression (IIFE), namely () {} ()
Indent trimming
val world = "multiline world" println( """ Hello \$world """.trimIndent() )
a)
Hello $world
b)
Hello $world
c)
Hello \multiline world
d)
Doesn't compile
Answer: C
In Kotlin, raw string is defined by a three quotation mark (""), does not contain escape, but can contain newline characters and any other characters. Even if there is an escape character \, string cannot be used there. If we have to show a string, we need to use KaTeX parse error: Expected '}', got 'EOF' at end of input: {''} 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)
a) negative,zero,positive
b) negative,zero,
c) negative,positive
d) ,zero,positive
Answer: D
, zero , positive
Remember, after processing by the Java compiler, the else if structure is actually processed by calling else with a "single line" if, that is, no matter how many else if, it will actually be converted into nesting in else. In Kotlin, functions are parsed before if else blocks, 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 wrap the entire if... Else... In parentheses and then add let.
Lambda runnables
fun run() { val run: () -> Unit = { println("Run run run!") } Runnable { run() }.run() } Call: run()
a) "Run run run!"
b) Doesn't compile
c) StackOverflowError
d) None of the above
Answer: A
This question is actually about the use of Kotlin local functions. The above code is actually equivalent to the following code:
val run1: () -> Unit = { println("Run run run!") } fun run() { Runnable { run1() }.run() }
Using local functions, you can hide logic inside functions.
Making open abstract
open class A { open fun a() {} } abstract class B: A() { abstract override fun a() } open class C: B()
a) Compiles fine
b) Error: Class 'C' is not abstract and does not implement abstract base class member
c) Error: 'a' overrides nothing
d) Error: Function 'a' must have a body
Answer: B
We can override an open function with an abstract function, but it is still abstract. We need to override the methods to be implemented in all subclasses, and the following code can 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()
**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))
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][][]
Answer: B
This question is actually to investigate the implementation of the minus function. In Kotlin:
List****minus T: remove the first matching element.
List****minus List: remove all elements existing in the second list from the first list.
Composition
operator fun (() -> Unit).plus(f: () -> Unit): () -> Unit = { this() f() } ({ print("Hello, ") } + { print("World") })()
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 definition of operator overloaded function plus is completely correct. It returns a new function (created using a lambda expression) consisting 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 called.
What am I?
val whatAmI = {}() println(whatAmI)
a) "null"
b) "kotlin.Unit"
c) Doesn't print anything
d) Doesn't compile
Answer: B
This question examines the basic knowledge of lambda expression. This lambda expression does not return content, so its type is Unit.
Return return
fun f1(): Int { return return 42 } fun f2() { throw throw Exception() }
Can f1 and f2 be executed?
a) returns 42; throws exception
b) returns 42; doesn't compile
c) doesn't compile; throws exception
d) doesn't compile; doesn't compile
Answer: A
The first return in f1 is actually invalid. If it is in the IDE, Lint will prompt.
The return expression has a return type and can be used as an expression. In f1, it also ends the execution of f1 with result 42. Similarly, throw declares the type - Nothing is also a return type, so both functions can be compiled, but when f2 is called, it will end with an exception.
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())
a) Doesn't compile
b) Runtime error
c) c
d) d
Answer: C
This example examines the specific implementation principle of the extension function. Because the called extension function only depends on the declaration type of parameter C, that is, class C, it will only call the extension function foo of class C.
Extensions do not actually modify the classes they extend. By defining an extension function, you don't really insert new members into a class, but just let the new function be called with a dot on this type of variable, which is equivalent to a layer of 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) }
What are the results of f1, f2 and f3?
a)
42 () -> kotlin.Int class C
b)
42 () -> kotlin.Int doesn't compile
c)
doesn't compile () -> kotlin.Int doesn't compile
d)
doesn't compile doesn't compile doesn't compile
Answer: C
Variable initialization and class declaration are statements in Kotlin. They do not declare any return type, so we can't assign this declaration to variables, so we can't compile. In f2, we actually implement an anonymous function, so we output a function.
Eager or lazy?
val x = listOf(1, 2, 3).filter { print("$it ") it >= 2 } print("before sum ") println(x.sum())
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 Java 8, the collection extension function in Kotlin is Eager's. If you need to use Lazy mode, you can use sequenceOf or asSequence. Both sequences are initialized with inertia.
Map default
val map = mapOf<Any, Any>().withDefault { "default" } println(map["1"])
a) default
b) nothing
c) null
d) will not compile*
Answer: C
Don't be fooled by the literal meaning of withDefault. withDefault can only be used in delegated attribute scenarios. Therefore, for unknown extension functions, you must go in and see the implementation. You can't guess.
val map = mutableMapOf<String, Set<String>>().withDefault { mutableSetOf() } var property: Set<String> by map // returns empty set by default
Null empty
val s: String? = null if (s?.isEmpty()) println("is empty") if (s.isNullOrEmpty()) println("is null or empty")
a) is empty is null or empty
b) is null or empty
c) prints nothing
d) doesn't compile
Answer: D
When s == null, s Isempty() will return null, so the return type of this expression should be Boolean?, Therefore, it cannot be compiled. 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") }
List or not
val x = listOf(1, 2, 3) println(x is List<*>) println(x is MutableList<*>) println(x is java.util.List<*>)
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 their types are the same.
Everything is mutable
val readonly = listOf(1, 2, 3) if (readonly is MutableList) { readonly.add(4) } println(readonly)
a) [1, 2, 3]
b) [1, 2, 3, 4]
c) UnsupportedOperationException
d) Will not compile
Answer: C
Similar to listOf and array Helper functions such as aslist () return Java util. Arrays $arraylis, not Java util. ArrayList, so they cannot 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 equilibrum = one then double then (increment + bicrement) println(equilibrum())
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 the pair generated by one or two functions. Therefore, we all start with {1} and become 2 through the then infix operator double. In plus, it is executed as 3 and 4 respectively.
❝
The case comes from puzzlers on KT Academy
❞
Many people say that what is the use of these things? A lot of code can be put in the IDE to know whether it is right or wrong and what the running result is. Why do you do this?
In fact, understanding these things will be very helpful to your programming thinking and language understanding. In the IDE, it has helped us do so many things that we can't really find out the essence of the problem. With the training of these problems, we can understand how the compiler handles the code and how the code is executed, That's why we train these subjects.
so, did you live to the end of this squid game?
Don't panic, there's the next episode!