誤入Android開發-Day2:Kotlin語法

影山小麥機
13 min readJul 26, 2024

果然一切還是從語法開始

前言

最近碰Flutter後,發現原生的知識Domain真的很重要,就算可能會flutter可以一次切兩版的方便性,在沒有良好的辨識原生機制的能力下,可能會產生很多意外旅程。至少我就處理過不少意外..

對於一個從iOS原生開發者轉向Flutter開發後,其實偶爾會有這樣的想法,所以也就打開了求職網站,掃了一下現在有哪些Android職缺。

也幸運的,就得到了Offer,轉向Android開發。

R,原本是二刀流iOS/Flutter,現在要變成iOS/Android/Flutter一起的三刀流開發者了。

那在上工前,至少也要讀讀Android的東西,我想也算預習可能在Android的基本開發方式上有一些基本的見解。

那接下來這段熟悉的旅程大概就會分成10天份左右點到為止的帶過,不過有的可能:

1. Android Studio基本開發(這部分可能隨緣?)
2. Kotlin語法
3. JetPack Compose
4. Android 事件流吧?

正文

就算語法再怎麼簡單,也還是稍微帶過一下,繼Swift、Dart之後,Kotlin已經是第三個語言了,其實語言大同小異,但在使用上仍舊有它微小的差異,老實說,寫到一定的程度,換一個語言其實看的都是模板,每個邏輯模板都會有它邏輯模板的特性。不過,通常我還是都會去熟悉一下這個語言的一些寫法,這樣比較容易快速開發。

這邊接下來簡單帶過一些語法概念:

常數

val name: String = "John"

變數

var age: Int = 30

如果要print值出來的話,可以用$寫成下面這樣:

val name = "Kotlin"
println("Hello, $name!")
// 輸出:Hello, Kotlin!

Lazy

使用 lazy 委託來實現遞延屬性。

val lazyValue: String by lazy {
println("Computed!")
"Hello"
}

println(lazyValue) // 輸出:Computed! Hello
println(lazyValue) // 輸出:Hello

函數 Functions

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

// 然後可以簡化成下面的寫法:
fun sum(a: Int, b: Int) = a + b

1. 預設參數 (Default Arguments)

函數可以有預設參數,這使得函數調用更加靈活。

fun greet(name: String, greeting: String = "Hello") {
println("$greeting, $name!")
}

greet("Alice") // 輸出:Hello, Alice!
greet("Bob", "Hi") // 輸出:Hi, Bob!

2. 命名參數 (Named Arguments)

在調用函數時,可以使用參數名稱來傳遞值,這使得代碼更具可讀性。

fun printPersonDetails(name: String, age: Int, city: String) {
println("Name: $name, Age: $age, City: $city")
}

printPersonDetails(name = "Alice", age = 30, city = "New York")

3. 擴展函數 (Extension Functions)

擴展函數允許你向現有的類型添加新功能,而不需要繼承或修改它們。

fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}

val email = "example@example.com"
println(email.isEmail()) // 輸出:true

條件邏輯Logic

單純的if…else…

val a = 10
val b = 20

if (a > b) {
println("a is greater than b")
} else {
println("a is less than or equal to b")
}

作為表達式使用:

Kotlin 中的 if-else 可以返回一個值,這樣可以簡化一些代碼邏輯。

val max = if (a > b) {
a
} else {
b
}

println("The maximum value is $max")

使用 if-else if 結構:

val x = 50

val result = if (x < 0) {
"Negative"
} else if (x == 0) {
"Zero"
} else {
"Positive"
}

println(result) // 輸出:Positive

簡寫:如果 if-else 只有一行語句,可以省略大括號:

val y = 15
val isEven = if (y % 2 == 0) "Even" else "Odd"
println(isEven) // 輸出:Odd

結合 when 表達式

當有多個條件時,when 表達式通常比多個 if-else if 更加清晰和易讀:

val number = 3

val numberType = when {
number < 0 -> "Negative"
number == 0 -> "Zero"
number % 2 == 0 -> "Even"
else -> "Odd"
}

println(numberType) // 輸出:Odd

循環迴圈Loop

// for 循環
for (item in items) {
println(item)
}

// while 循環
while (x > 0) {
x--
}

實例:

for (i in 1..5) {
println(i) // 輸出:1 2 3 4 5
}

val x = 10
if (x in 1..20) {
println("$x is in the range") // 輸出:10 is in the range
}

閉包(Lambda)

1.簡單的 Lambda 表達式

val lambdaName: (參數類型) -> 返回值類型 = { 參數 -> 函數體 }

2.作為函數參數的 Lambda 表達式

// 定義一個函數,接受一個 Lambda 表達式作為參數
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

val result = calculate(5, 7, { a, b -> a * b })
println(result) // 輸出:35

3.集合操作中的 Lambda 表達式

Lambda 表達式在集合操作中非常有用,比如 map、filter 等函數:

val numbers = listOf(1, 2, 3, 4, 5)

// 使用 Lambda 表達式將所有元素乘以 2
val doubled = numbers.map { it * 2 }
println(doubled) // 輸出:[2, 4, 6, 8, 10]

// 使用 Lambda 表達式過濾掉所有奇數
val evenNumbers = numbers.filter { it % 2 == 0 }
println(evenNumbers) // 輸出:[2, 4]

4.Lambda 表達式中的閉包

Lambda 表達式可以訪問其所在作用域內的變量,這種特性稱為閉包:

var factor = 2
val multiply: (Int) -> Int = { number -> number * factor }

println(multiply(3)) // 輸出:6

factor = 3
println(multiply(3)) // 輸出:9

5.高階函數和 Lambda 表達式

高階函數是接受函數作為參數或返回函數的函數,Lambda 表達式在這裡非常有用:

fun performOperation(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

val add: (Int, Int) -> Int = { a, b -> a + b }
val subtract: (Int, Int) -> Int = { a, b -> a - b }

println(performOperation(10, 5, add)) // 輸出:15
println(performOperation(10, 5, subtract)) // 輸出:5

6.Lambda 表達式與 it 關鍵字

當 Lambda 表達式只有一個參數時,可以使用 it 關鍵字來引用該參數:

val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
println(doubled) // 輸出:[2, 4, 6, 8, 10]

7:Lambda 表達式與匿名函數

val sum = fun(a: Int, b: Int): Int = a + b
println(sum(3, 4)) // 輸出:7

物件Class

初始化一個物件就是下面這個樣子,不過我猜應該還有其他輔助前綴字可以定義這個初始化物件的性質:

class Person(val name: String, var age: Int)

val person = Person("Alice", 29)
println(person.name) // 輸出:Alice

解構聲明 (Destructuring Declarations)

解構聲明允許從對象中提取多個值。

data class Person(val name: String, val age: Int)

val person = Person("Alice", 30)
val (name, age) = person
println("Name: $name, Age: $age") // 輸出:Name: Alice, Age: 30

成員引用 (Member References)

fun greetPerson(name: String) {
println("Hello, $name!")
}

val greeter: (String) -> Unit = ::greetPerson
greeter("Alice") // 輸出:Hello, Alice!

物件委託(Delegation)

Kotlin 支持物件委託,使得一個類可以將其部分功能委託給另一個對象。

interface SoundBehavior {
fun makeSound()
}

class Dog : SoundBehavior {
override fun makeSound() {
println("Bark")
}
}

class Cat : SoundBehavior {
override fun makeSound() {
println("Meow")
}
}

class Animal(soundBehavior: SoundBehavior) : SoundBehavior by soundBehavior

val dog = Animal(Dog())
dog.makeSound() // 輸出:Bark

val cat = Animal(Cat())
cat.makeSound() // 輸出:Meow

繼承關係

Kotlin 中的類默認是 final,如果需要允許繼承,必須使用 open 關鍵字,這樣就可以讓這個物件被其他的子類繼承:

open class Animal(val name: String) {
open fun sound() {
println("Animal sound")
}
}

class Dog(name: String) : Animal(name) {
override fun sound() {
println("Bark")
}
}

val dog = Dog("Buddy")
dog.sound() // 輸出:Bark

單例(Singleton)

Kotlin 提供了 object 關鍵字來創建單例對象。

object Database {
val name = "MyDatabase"
fun connect() {
println("Connected to $name")
}
}

Database.connect() // 輸出:Connected to MyDatabase

可選(空安全)Optional

我實在不清楚要怎麼形容這個語法特性,但就是Swift的Optional

var nullable: String? = "Hello"
nullable = null // 可以賦值為 null

// 使用 ?. 來調用方法
println(nullable?.length) // 輸出:null

// 使用 !! 來確保非空
println(nullable!!.length) // 可能會拋出 NullPointerException

這邊有比較多的細節操作,如下:
1. 安全調用操作符 (?.)

val length: Int? = nullableString?.length
println(length) // 如果 nullableString 為 null,則 length 也為 null

2. Elvis 操作符 (?:)

val length: Int = nullableString?.length ?: 0
println(length) // 如果 nullableString 為 null,則 length 為 0

3. 非空斷言操作符 (!!)

val length: Int = nullableString!!.length
println(length) // 如果 nullableString 為 null,則會拋出 NullPointerException

4. 安全類型轉換 (as?)

val obj: Any = "Hello"
val str: String? = obj as? String
println(str) // str 為 "Hello",如果轉換失敗,則 str 為 null

5. 使用 let 函數

Kotlin 還提供了一個擴展函數 let,可以用於處理非空值。

nullableString?.let {
println(it.length) // 如果 nullableString 不為 null,則執行這段代碼
}

同樣概念的Swift Code:

var optionalString: String? = "Hello"
if let unwrappedString = optionalString {
print(unwrappedString) // 輸出:Hello
}

泛型 (Generics)

class Box<T>(val value: T)

val intBox = Box(1)
val stringBox = Box("Hello")

println(intBox.value) // 輸出:1
println(stringBox.value) // 輸出:Hello

小結

大抵上Kotlin的用法跟Swift很像,為了開發方便,其實蠻多相似性的。不過語法雖有相異處,但還是在閱讀上相當方便,跟Swift一樣比起Object-C,以及相較Kotlin比起Java而言,有更高幅度的可讀性。

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

影山小麥機
影山小麥機

Written by 影山小麥機

本職為Mobile工程師,熱愛分享視野,也樂意站在ChatGPT的肩膀上。訂閱小麥機,收割技術、職涯、人生的難題。

No responses yet

Write a response