果然一切還是從語法開始

前言
最近碰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而言,有更高幅度的可讀性。