Swift 語法學習指南 - 與 Kotlin 對比

Swift 語法學習指南 - 與 Kotlin 對比

本指南專為有 Android/Kotlin 開發經驗的開發者設計,通過對比學習快速掌握 Swift 語法

目錄

  1. 語言基礎對比
  2. 變量與常量
  3. 數據類型
  4. 函數定義
  5. 類與結構體
  6. 繼承與協議
  7. 可選類型
  8. 集合類型
  9. 控制流
  10. 閉包與Lambda
  11. 擴展與Extension
  12. 錯誤處理
  13. 內存管理
  14. 實戰練習

語言基礎對比

基本特性對比

特性SwiftKotlin
類型推斷? 強類型推斷? 強類型推斷
空安全? Optional 類型? Nullable 類型
函數式編程? 支持? 支持
面向對象? 支持? 支持
協議/接口ProtocolInterface
擴展ExtensionExtension Function

變量與常量

Swift

// 常量 - 不可變
let name = "張三"           // 類型推斷
let age: Int = 25          // 顯式類型// 變量 - 可變
var score = 90
var height: Double = 175.5// 延遲初始化
lazy var expensiveResource = createResource()

Kotlin

// 常量 - 不可變
val name = "張三"           // 類型推斷
val age: Int = 25          // 顯式類型// 變量 - 可變
var score = 90
var height: Double = 175.5// 延遲初始化
val expensiveResource by lazy { createResource() }

對比總結

  • Swift 使用 let/var,Kotlin 使用 val/var
  • 兩者都支持類型推斷
  • Swift 的 lazy 是關鍵字,Kotlin 使用 by lazy 委托

數據類型

基本數據類型對比

類型SwiftKotlin
整數Int, Int8, Int16, Int32, Int64Int, Byte, Short, Int, Long
浮點Float, DoubleFloat, Double
布爾BoolBoolean
字符CharacterChar
字符串StringString

字符串操作

Swift
// 字符串插值
let name = "Swift"
let message = "Hello, \(name)!"// 多行字符串
let multiline = """
這是一個
多行字符串
"""// 字符串方法
let text = "Hello World"
print(text.count)                    // 長度
print(text.uppercased())            // 大寫
print(text.contains("World"))       // 包含
Kotlin
// 字符串插值
val name = "Kotlin"
val message = "Hello, $name!"
val complexMessage = "Hello, ${name.uppercase()}!"// 多行字符串
val multiline = """這是一個多行字符串
""".trimIndent()// 字符串方法
val text = "Hello World"
println(text.length)                 // 長度
println(text.uppercase())           // 大寫
println(text.contains("World"))     // 包含

協議屬性聲明詳解

為什么協議中必須使用 var 而不是 let

Swift 協議中的屬性聲明有特殊的語法規則:

1. 協議屬性聲明規則
protocol MyProtocol {// ? 正確:只讀屬性var readOnlyProperty: String { get }// ? 正確:可讀寫屬性var readWriteProperty: Int { get set }// ? 錯誤:協議中不能使用 let// let constantProperty: String { get }  // 編譯錯誤
}
2. 實現協議時的靈活性
class MyClass: MyProtocol {// 只讀屬性可以用 let 實現let readOnlyProperty: String = "Hello"// 也可以用 var 實現var anotherReadOnly: String {return "World"}// 可讀寫屬性必須用 var 實現var readWriteProperty: Int = 42
}
3. 與 Kotlin 的對比
特性Swift 協議Kotlin 接口
只讀屬性聲明var property: Type { get }val property: Type
可讀寫屬性聲明var property: Type { get set }var property: Type
實現只讀屬性可用 letvar可用 valvar
實現可讀寫屬性必須用 var必須用 var
4. 核心要點
  • 協議聲明:Swift 協議中所有屬性都必須用 var 聲明
  • 訪問控制:通過 { get }{ get set } 指定屬性的訪問權限
  • 實現靈活性:只讀屬性({ get })在實現時可以是 let 常量
  • 類型安全:編譯器確保實現類滿足協議的訪問權限要求

這種設計讓 Swift 協議既保持了靈活性,又確保了類型安全。


函數定義

Swift

// 基本函數
func greet(name: String) -> String {return "Hello, \(name)!"
}// 帶默認參數
func greet(name: String, age: Int = 18) -> String {return "Hello, \(name), you are \(age) years old"
}// 可變參數
func sum(_ numbers: Int...) -> Int {return numbers.reduce(0, +)
}// 高階函數
func processData(_ data: [Int], processor: (Int) -> Int) -> [Int] {return data.map(processor)
}// 調用
let result1 = greet(name: "張三")
let result2 = greet(name: "李四", age: 25)
let total = sum(1, 2, 3, 4, 5)

Kotlin

// 基本函數
fun greet(name: String): String {return "Hello, $name!"
}// 帶默認參數
fun greet(name: String, age: Int = 18): String {return "Hello, $name, you are $age years old"
}// 可變參數
fun sum(vararg numbers: Int): Int {return numbers.sum()
}// 高階函數
fun processData(data: List<Int>, processor: (Int) -> Int): List<Int> {return data.map(processor)
}// 調用
val result1 = greet("張三")
val result2 = greet("李四", 25)
val total = sum(1, 2, 3, 4, 5)

對比總結

  • Swift 使用 func 關鍵字,Kotlin 使用 fun
  • Swift 參數標簽更靈活,Kotlin 相對簡單
  • Swift 可變參數用 ...,Kotlin 用 vararg

類與結構體

Swift

// 結構體(值類型)
struct Point {var x: Doublevar y: Double// 計算屬性var distance: Double {return sqrt(x * x + y * y)}// 方法// mutating 關鍵字說明:// 在 Swift 中,結構體(struct)是值類型,默認情況下其方法不能修改實例的屬性// 如果需要在方法中修改結構體的屬性,必須使用 mutating 關鍵字標記該方法// 這是 Swift 的安全機制,確保值類型的不可變性,除非明確聲明為可變mutating func moveBy(x deltaX: Double, y deltaY: Double) {x += deltaX  // 修改實例屬性 xy += deltaY  // 修改實例屬性 y}
}// 類(引用類型)
class Person {var name: Stringvar age: Int// 構造器init(name: String, age: Int) {self.name = nameself.age = age}// 方法func introduce() -> String {return "我是\(name),今年\(age)歲"}
}// 使用
var point = Point(x: 3.0, y: 4.0)
print(point.distance)  // 5.0
point.moveBy(x: 1.0, y: 1.0)let person = Person(name: "張三", age: 25)
print(person.introduce())

Kotlin

// 數據類(類似結構體)
data class Point(var x: Double,var y: Double
) {// 計算屬性val distance: Doubleget() = sqrt(x * x + y * y)// 方法fun moveBy(deltaX: Double, deltaY: Double) {x += deltaXy += deltaY}
}// 類
class Person(var name: String,var age: Int
) {// 方法fun introduce(): String {return "我是$name,今年${age}歲"}
}// 使用
val point = Point(3.0, 4.0)
println(point.distance)  // 5.0
point.moveBy(1.0, 1.0)val person = Person("張三", 25)
println(person.introduce())

mutating 關鍵字詳解

Swift 中的 mutating

mutating 是 Swift 中一個重要的關鍵字,專門用于值類型(struct 和 enum):

struct Counter {var count = 0// ? 錯誤:不能在非 mutating 方法中修改屬性// func increment() {//     count += 1  // 編譯錯誤// }// ? 正確:使用 mutating 關鍵字mutating func increment() {count += 1  // 可以修改屬性}mutating func reset() {count = 0}// 不修改屬性的方法不需要 mutatingfunc getCurrentCount() -> Int {return count}
}// 使用示例
var counter = Counter()  // 注意:必須是 var,不能是 let
counter.increment()      // count = 1
counter.increment()      // count = 2
print(counter.getCurrentCount())  // 2// let counter2 = Counter()
// counter2.increment()  // ? 編譯錯誤:let 常量不能調用 mutating 方法
與 Kotlin 的對比
特性SwiftKotlin
值類型可變性需要 mutating 關鍵字明確標記直接修改,無需特殊標記
編譯時檢查嚴格檢查,防止意外修改相對寬松
常量實例let 實例不能調用 mutating 方法val 實例仍可修改內部可變屬性
安全性更高的類型安全性依賴開發者自覺
為什么需要 mutating?
  1. 值類型的不可變性:Swift 的 struct 是值類型,默認不可變
  2. 明確的意圖表達mutating 明確表示該方法會修改實例
  3. 編譯時安全:防止意外修改,提高代碼安全性
  4. 函數式編程支持:鼓勵不可變編程風格
實際應用場景
struct BankAccount {private var balance: Doubleinit(initialBalance: Double) {self.balance = initialBalance}// 查詢余額 - 不需要 mutatingfunc getBalance() -> Double {return balance}// 存款 - 需要 mutatingmutating func deposit(amount: Double) {guard amount > 0 else { return }balance += amount}// 取款 - 需要 mutatingmutating func withdraw(amount: Double) -> Bool {guard amount > 0 && amount <= balance else {return false}balance -= amountreturn true}
}var account = BankAccount(initialBalance: 1000.0)
print(account.getBalance())  // 1000.0
account.deposit(amount: 500.0)
print(account.getBalance())  // 1500.0
let success = account.withdraw(amount: 200.0)
print(account.getBalance())  // 1300.0

繼承與協議

Swift

// 協議定義
protocol Drawable {func draw()// 注意:協議中的屬性聲明必須使用 var,不能使用 let// { get } 表示這是一個只讀屬性,實現時可以是 let 常量或 var 變量// 但在協議聲明中必須用 var,因為協議不知道具體實現方式var area: Double { get }
}protocol Colorable {// { get set } 表示這是一個可讀寫屬性,實現時必須是 var 變量var color: String { get set }
}// 基類
class Shape: Drawable {var area: Double {return 0.0}func draw() {print("繪制形狀")}
}// 繼承和協議實現
class Circle: Shape, Colorable {var radius: Doublevar color: Stringinit(radius: Double, color: String) {self.radius = radiusself.color = colorsuper.init()}override var area: Double {return Double.pi * radius * radius}override func draw() {print("繪制\(color)的圓形")}
}

Kotlin

// 接口定義
interface Drawable {fun draw()val area: Double
}interface Colorable {var color: String
}// 基類
open class Shape : Drawable {override val area: Doubleget() = 0.0override fun draw() {println("繪制形狀")}
}// 繼承和接口實現
class Circle(val radius: Double,override var color: String
) : Shape(), Colorable {override val area: Doubleget() = Math.PI * radius * radiusoverride fun draw() {println("繪制${color}的圓形")}
}

可選類型

Swift Optional

// 可選類型聲明
var optionalName: String? = "張三"
var optionalAge: Int? = nil// 可選綁定
if let name = optionalName {// \(name) 是字符串插值,name 是變量調用// 在字符串插值中可以調用屬性、方法和擴展函數print("姓名是: \(name)")print("姓名長度: \(name.count)")  // 調用屬性print("大寫姓名: \(name.uppercased())")  // 調用方法
} else {print("姓名為空")
}// guard 語句
func processUser(name: String?) {guard let userName = name else {print("用戶名不能為空")return}print("處理用戶: \(userName)")
}// 空合并運算符
let displayName = optionalName ?? "未知用戶"// 強制解包(危險操作)
let forcedName = optionalName!  // 如果為nil會崩潰// 可選鏈
class Person {var address: Address?
}class Address {var street: String?
}let person: Person? = Person()
let street = person?.address?.street  // 可選鏈調用

Kotlin Nullable

// 可空類型聲明
var optionalName: String? = "張三"
var optionalAge: Int? = null// 安全調用
optionalName?.let { name ->println("姓名是: $name")
} ?: run {println("姓名為空")
}// Elvis 運算符
val displayName = optionalName ?: "未知用戶"// 非空斷言(危險操作)
val forcedName = optionalName!!  // 如果為null會拋異常// 安全調用鏈
class Person {var address: Address? = null
}class Address {var street: String? = null
}val person: Person? = Person()
val street = person?.address?.street  // 安全調用鏈

對比總結

  • Swift 使用 ?!,Kotlin 也使用 ?!!
  • Swift 的 if let 對應 Kotlin 的 ?.let
  • Swift 的 ?? 對應 Kotlin 的 ?:

字符串插值與擴展函數調用

回答你的問題:是的,\(name) 是對變量的調用,而且在字符串插值中可以調用屬性、方法和擴展函數。

Swift 字符串插值
let name = "張三"
let age = 25// 基本變量調用
print("姓名: \(name)")// 調用屬性和方法
print("姓名長度: \(name.count)")
print("大寫姓名: \(name.uppercased())")
print("年齡加10: \(age + 10)")// 調用擴展函數
extension String {func addPrefix(_ prefix: String) -> String {return prefix + self}
}print("帶前綴的姓名: \(name.addPrefix("Mr. "))")// 復雜表達式
print("信息: \(name.isEmpty ? "無名" : name.uppercased())")
Kotlin 字符串模板
val name = "張三"
val age = 25// 基本變量調用
println("姓名: $name")// 調用屬性和方法
println("姓名長度: ${name.length}")
println("大寫姓名: ${name.uppercase()}")
println("年齡加10: ${age + 10}")// 調用擴展函數
fun String.addPrefix(prefix: String): String {return prefix + this
}println("帶前綴的姓名: ${name.addPrefix("Mr. ")}")// 復雜表達式
println("信息: ${if (name.isEmpty()) "無名" else name.uppercase()}")
對比總結
特性SwiftKotlin
基本語法\(variable)$variable
復雜表達式\(expression)${expression}
方法調用\(obj.method())${obj.method()}
擴展函數\(obj.extensionFunc())${obj.extensionFunc()}
條件表達式\(condition ? a : b)${if (condition) a else b}
核心要點
  • 變量調用:字符串插值中的變量是正常的變量訪問
  • 方法鏈式調用:可以在插值中進行鏈式方法調用
  • 擴展函數支持:完全支持調用擴展函數
  • 表達式計算:插值內可以進行復雜的表達式計算
  • 類型安全:編譯時檢查確保類型正確

集合類型

Swift

// 數組
var numbers = [1, 2, 3, 4, 5]
var strings: [String] = ["a", "b", "c"]// 數組操作
numbers.append(6)
numbers.insert(0, at: 0)
let first = numbers.first  // Optional<Int>
let count = numbers.count// 字典
var scores = ["張三": 95, "李四": 87]
var ages: [String: Int] = [:]// 字典操作
scores["王五"] = 92
let zhangScore = scores["張三"]  // Optional<Int>// 集合
var uniqueNumbers: Set<Int> = [1, 2, 3, 3, 4]  // {1, 2, 3, 4}// 高階函數
let doubled = numbers.map { $0 * 2 }
let evens = numbers.filter { $0 % 2 == 0 }
let sum = numbers.reduce(0, +)

Kotlin

// 列表
val numbers = mutableListOf(1, 2, 3, 4, 5)
val strings: List<String> = listOf("a", "b", "c")// 列表操作
numbers.add(6)
numbers.add(0, 0)
val first = numbers.firstOrNull()  // Int?
val count = numbers.size// 映射
val scores = mutableMapOf("張三" to 95, "李四" to 87)
val ages: MutableMap<String, Int> = mutableMapOf()// 映射操作
scores["王五"] = 92
val zhangScore = scores["張三"]  // Int?// 集合
val uniqueNumbers: Set<Int> = setOf(1, 2, 3, 3, 4)  // {1, 2, 3, 4}// 高階函數
val doubled = numbers.map { it * 2 }
val evens = numbers.filter { it % 2 == 0 }
val sum = numbers.reduce { acc, n -> acc + n }

控制流

Swift

// if-else
let score = 85
if score >= 90 {print("優秀")
} else if score >= 80 {print("良好")
} else {print("需要努力")
}// switch
let grade = "A"
switch grade {case "A":print("優秀")case "B", "C":print("良好")case "D":print("及格")default:print("不及格")
}// for 循環
for i in 1...5 {print(i)
}for i in 1..<5 {print(i)  // 1, 2, 3, 4
}for (index, value) in ["a", "b", "c"].enumerated() {print("\(index): \(value)")
}// while 循環
var count = 0
while count < 5 {print(count)count += 1
}

Kotlin

// if-else
val score = 85
if (score >= 90) {println("優秀")
} else if (score >= 80) {println("良好")
} else {println("需要努力")
}// when (類似 switch)
val grade = "A"
when (grade) {"A" -> println("優秀")"B", "C" -> println("良好")"D" -> println("及格")else -> println("不及格")
}// for 循環
for (i in 1..5) {println(i)
}for (i in 1 until 5) {println(i)  // 1, 2, 3, 4
}for ((index, value) in listOf("a", "b", "c").withIndex()) {println("$index: $value")
}// while 循環
var count = 0
while (count < 5) {println(count)count++
}

閉包與Lambda

Swift 閉包

// 基本閉包語法
let numbers = [1, 2, 3, 4, 5]// 完整語法
let doubled1 = numbers.map({ (number: Int) -> Int inreturn number * 2
})// 簡化語法
let doubled2 = numbers.map { number inreturn number * 2
}// 最簡語法
let doubled3 = numbers.map { $0 * 2 }// 尾隨閉包
let filtered = numbers.filter { $0 % 2 == 0 }// 捕獲值
func makeIncrementer(incrementAmount: Int) -> () -> Int {var total = 0let incrementer: () -> Int = {total += incrementAmountreturn total}return incrementer
}let incrementByTwo = makeIncrementer(incrementAmount: 2)
print(incrementByTwo())  // 2
print(incrementByTwo())  // 4

Kotlin Lambda

// 基本 Lambda 語法
val numbers = listOf(1, 2, 3, 4, 5)// 完整語法
val doubled1 = numbers.map({ number: Int -> number * 2 })// 簡化語法
val doubled2 = numbers.map { number -> number * 2 }// 最簡語法(使用 it)
val doubled3 = numbers.map { it * 2 }// 過濾
val filtered = numbers.filter { it % 2 == 0 }// 捕獲值
fun makeIncrementer(incrementAmount: Int): () -> Int {var total = 0return {total += incrementAmounttotal}
}val incrementByTwo = makeIncrementer(2)
println(incrementByTwo())  // 2
println(incrementByTwo())  // 4

擴展與Extension

Swift Extension

// 擴展基本類型
extension String {var isEmail: Bool {return self.contains("@") && self.contains(".")}func reversed() -> String {return String(self.reversed())}
}// 擴展自定義類型
extension Person {func greet() -> String {return "Hello, I'm \(name)"}var isAdult: Bool {return age >= 18}
}// 使用擴展
let email = "test@example.com"
print(email.isEmail)  // true
print("Swift".reversed())  // tfiwSlet person = Person(name: "張三", age: 20)
print(person.greet())
print(person.isAdult)

Kotlin Extension

// 擴展基本類型
val String.isEmail: Booleanget() = this.contains("@") && this.contains(".")fun String.reversed(): String {return this.reversed()
}// 擴展自定義類型
fun Person.greet(): String {return "Hello, I'm $name"
}val Person.isAdult: Booleanget() = age >= 18// 使用擴展
val email = "test@example.com"
println(email.isEmail)  // true
println("Kotlin".reversed())  // niltoKval person = Person("張三", 20)
println(person.greet())
println(person.isAdult)

錯誤處理

Swift 錯誤處理

// 定義錯誤類型
enum ValidationError: Error {case emptyNamecase invalidAgecase invalidEmail
}// 可能拋出錯誤的函數
func validateUser(name: String, age: Int, email: String) throws -> Bool {if name.isEmpty {throw ValidationError.emptyName}if age < 0 || age > 150 {throw ValidationError.invalidAge}if !email.contains("@") {throw ValidationError.invalidEmail}return true
}// 錯誤處理
do {try validateUser(name: "張三", age: 25, email: "zhang@example.com")print("用戶驗證成功")
} catch ValidationError.emptyName {print("姓名不能為空")
} catch ValidationError.invalidAge {print("年齡無效")
} catch ValidationError.invalidEmail {print("郵箱格式無效")
} catch {print("未知錯誤: \(error)")
}// try? 和 try!
let result1 = try? validateUser(name: "李四", age: 30, email: "li@example.com")
let result2 = try! validateUser(name: "王五", age: 28, email: "wang@example.com")

Kotlin 異常處理

// 自定義異常
class ValidationException(message: String) : Exception(message)// 可能拋出異常的函數
fun validateUser(name: String, age: Int, email: String): Boolean {if (name.isEmpty()) {throw ValidationException("姓名不能為空")}if (age < 0 || age > 150) {throw ValidationException("年齡無效")}if (!email.contains("@")) {throw ValidationException("郵箱格式無效")}return true
}// 異常處理
try {validateUser("張三", 25, "zhang@example.com")println("用戶驗證成功")
} catch (e: ValidationException) {println("驗證錯誤: ${e.message}")
} catch (e: Exception) {println("未知錯誤: ${e.message}")
}// runCatching (類似 try?)
val result = runCatching {validateUser("李四", 30, "li@example.com")
}.getOrNull()

內存管理

Swift ARC (自動引用計數)

class Person {let name: Stringvar apartment: Apartment?init(name: String) {self.name = name}deinit {print("\(name) 被釋放")}
}class Apartment {let unit: Stringweak var tenant: Person?  // 弱引用避免循環引用init(unit: String) {self.unit = unit}deinit {print("公寓 \(unit) 被釋放")}
}// 使用
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")john?.apartment = unit4A
unit4A?.tenant = john// 釋放引用 - Swift ARC 需要手動打破循環引用
// 如果不手動置 nil,即使使用了 weak 引用,外部強引用仍然存在
john = nil    // 釋放 Person 實例的強引用
unit4A = nil  // 釋放 Apartment 實例的強引用

Kotlin GC (垃圾回收)

class Person(val name: String) {var apartment: Apartment? = nullprotected fun finalize() {println("$name 被回收")}
}class Apartment(val unit: String) {var tenant: Person? = null  // Kotlin 的 GC 會處理循環引用protected fun finalize() {println("公寓 $unit 被回收")}
}// 使用
var john: Person? = Person("John")
var unit4A: Apartment? = Apartment("4A")john?.apartment = unit4A
unit4A?.tenant = john// 釋放引用 - Kotlin GC 可以自動處理循環引用
// 即使不手動置 null,GC 也能檢測并回收循環引用的對象
john = null  // 可選操作,GC 會自動處理
unit4A = null  // 可選操作,GC 會自動處理

Swift ARC vs Kotlin GC 對比

回答你的問題:你說得對!Kotlin 確實不需要手動置 null,而 Swift 在某些情況下需要。

內存管理機制對比
特性Swift ARCKotlin GC
管理方式自動引用計數垃圾回收器
循環引用處理需要 weak/unowned 引用自動檢測和處理
手動置 nil有時需要通常不需要
性能特點確定性釋放,低延遲可能有 GC 暫停
內存泄漏風險循環引用導致泄漏很少發生
具體差異說明

Swift ARC 的限制

// 即使使用了 weak 引用,外部強引用仍需手動釋放
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")john?.apartment = unit4A
unit4A?.tenant = john  // weak 引用// 必須手動置 nil,否則 john 和 unit4A 不會被釋放
john = nil    // 必需!
unit4A = nil  // 必需!

Kotlin GC 的優勢

// GC 可以自動檢測循環引用
var john: Person? = Person("John")
var unit4A: Apartment? = Apartment("4A")john?.apartment = unit4A
unit4A?.tenant = john  // 普通引用// 不需要手動置 null,GC 會自動處理
// john = null  // 可選
// unit4A = null  // 可選// 當這些變量超出作用域時,GC 會自動回收
核心要點
  • Swift:ARC 基于引用計數,無法自動處理循環引用,需要開發者使用 weak/unowned 和手動置 nil
  • Kotlin:GC 可以檢測并自動回收循環引用的對象,開發者無需特殊處理
  • 最佳實踐:Swift 中養成手動置 nil 的習慣,Kotlin 中可以依賴 GC 自動管理

這就是為什么 Swift 開發者需要更加注意內存管理,而 Kotlin/Java 開發者相對輕松一些。


實戰練習

練習1:創建一個簡單的學生管理系統

Swift 版本
struct Student {let id: Stringvar name: Stringvar age: Intvar scores: [String: Double]  // 科目: 分數var averageScore: Double {guard !scores.isEmpty else { return 0.0 }return scores.values.reduce(0, +) / Double(scores.count)}mutating func addScore(subject: String, score: Double) {scores[subject] = score}
}class StudentManager {private var students: [String: Student] = [:]func addStudent(_ student: Student) {students[student.id] = student}func getStudent(id: String) -> Student? {return students[id]}func getAllStudents() -> [Student] {return Array(students.values)}func getTopStudents(count: Int) -> [Student] {return getAllStudents().sorted { $0.averageScore > $1.averageScore }.prefix(count).map { $0 }}
}// 使用示例
let manager = StudentManager()var student1 = Student(id: "001", name: "張三", age: 20, scores: [:])
student1.addScore(subject: "數學", score: 95.0)
student1.addScore(subject: "英語", score: 87.0)manager.addStudent(student1)if let student = manager.getStudent(id: "001") {print("學生: \(student.name), 平均分: \(student.averageScore)")
}
Kotlin 版本
data class Student(val id: String,var name: String,var age: Int,private val scores: MutableMap<String, Double> = mutableMapOf()
) {val averageScore: Doubleget() = if (scores.isEmpty()) 0.0 else scores.values.average()fun addScore(subject: String, score: Double) {scores[subject] = score}fun getScores(): Map<String, Double> = scores.toMap()
}class StudentManager {private val students = mutableMapOf<String, Student>()fun addStudent(student: Student) {students[student.id] = student}fun getStudent(id: String): Student? {return students[id]}fun getAllStudents(): List<Student> {return students.values.toList()}fun getTopStudents(count: Int): List<Student> {return getAllStudents().sortedByDescending { it.averageScore }.take(count)}
}// 使用示例
val manager = StudentManager()val student1 = Student("001", "張三", 20)
student1.addScore("數學", 95.0)
student1.addScore("英語", 87.0)manager.addStudent(student1)manager.getStudent("001")?.let { student ->println("學生: ${student.name}, 平均分: ${student.averageScore}")
}

練習2:網絡請求封裝

Swift 版本
import Foundationenum NetworkError: Error {case invalidURLcase noDatacase decodingError
}class NetworkManager {static let shared = NetworkManager()private init() {}func request<T: Codable>(url: String,type: T.Type,completion: @escaping (Result<T, NetworkError>) -> Void) {// guard 語句:提前退出模式,確保條件滿足才繼續執行// 類似 Kotlin 的 require() 或 early return 模式guard let url = URL(string: url) else {completion(.failure(.invalidURL))return  // 條件不滿足時提前退出}URLSession.shared.dataTask(with: url) { data, response, error inguard let data = data else {completion(.failure(.noData))return}do {let result = try JSONDecoder().decode(type, from: data)completion(.success(result))} catch {completion(.failure(.decodingError))}}.resume()}
}// 使用示例
struct User: Codable {let id: Intlet name: Stringlet email: String
}NetworkManager.shared.request(url: "https://api.example.com/users/1",type: User.self
) { result inswitch result {case .success(let user):print("用戶: \(user.name)")case .failure(let error):print("錯誤: \(error)")}
}
Kotlin 版本
import kotlinx.coroutines.*
import kotlinx.serialization.*
import kotlinx.serialization.json.*sealed class NetworkResult<T> {data class Success<T>(val data: T) : NetworkResult<T>()data class Error<T>(val message: String) : NetworkResult<T>()
}class NetworkManager {companion object {val instance = NetworkManager()}private val json = Json { ignoreUnknownKeys = true }suspend inline fun <reified T> request(url: String): NetworkResult<T> {return withContext(Dispatchers.IO) {try {// 這里應該使用實際的 HTTP 客戶端,如 OkHttpval response = ""  // 模擬響應val result = json.decodeFromString<T>(response)NetworkResult.Success(result)} catch (e: Exception) {NetworkResult.Error(e.message ?: "Unknown error")}}}
}// 使用示例
@Serializable
data class User(val id: Int,val name: String,val email: String
)// 在協程中使用
GlobalScope.launch {when (val result = NetworkManager.instance.request<User>("https://api.example.com/users/1")) {is NetworkResult.Success -> {println("用戶: ${result.data.name}")}is NetworkResult.Error -> {println("錯誤: ${result.message}")}}
}

Guard 語句詳解

什么是 Guard 語句

guard 是 Swift 中的一個關鍵字,用于提前退出模式(Early Exit Pattern)。它確保某個條件必須為真,否則就提前退出當前作用域。

基本語法

guard 條件 else {// 條件不滿足時執行的代碼return  // 必須有退出語句
}
// 條件滿足時繼續執行的代碼

Guard vs If Let 對比

// 使用 if let(嵌套結構)
func processUser(name: String?) {if let userName = name {if userName.count > 0 {if userName != "admin" {print("處理用戶: \(userName)")// 更多邏輯...} else {print("管理員用戶")return}} else {print("用戶名為空")return}} else {print("用戶名為 nil")return}
}// 使用 guard(扁平結構)
func processUserWithGuard(name: String?) {guard let userName = name else {print("用戶名為 nil")return}guard userName.count > 0 else {print("用戶名為空")return}guard userName != "admin" else {print("管理員用戶")return}print("處理用戶: \(userName)")// 更多邏輯...
}

Guard 的優勢

  1. 減少嵌套:避免金字塔式的 if-else 嵌套
  2. 提高可讀性:主要邏輯更清晰
  3. 強制處理:必須在 else 塊中處理異常情況
  4. 作用域擴展:guard let 綁定的變量在后續代碼中可用

與 Kotlin 的對比

特性Swift GuardKotlin 等價寫法
提前退出guard condition else { return }if (!condition) return
空值檢查guard let value = optional else { return }val value = optional ?: return
條件驗證guard user.isValid else { return }require(user.isValid) { "Invalid user" }
多條件檢查多個 guard 語句takeIf { } 或多個 require
Kotlin 對應寫法示例
// Swift guard 對應的 Kotlin 寫法
fun processUser(name: String?) {// Swift: guard let userName = name else { return }val userName = name ?: return// Swift: guard userName.isNotEmpty() else { return }if (userName.isEmpty()) return// Swift: guard userName != "admin" else { return }require(userName != "admin") { "Admin user not allowed" }println("處理用戶: $userName")
}// 或者使用 takeIf
fun processUserWithTakeIf(name: String?) {name?.takeIf { it.isNotEmpty() }?.takeIf { it != "admin" }?.let { userName ->println("處理用戶: $userName")}
}

核心要點

  1. 必須退出:guard 的 else 塊必須包含 returnbreakcontinuethrow 等退出語句
  2. 扁平化代碼:避免深層嵌套,讓主要邏輯更突出
  3. 變量作用域:guard let 綁定的變量在整個函數剩余部分可用
  4. 錯誤處理:適合用于參數驗證和前置條件檢查
  5. Kotlin 替代:主要使用 ?: 操作符、require()takeIf() 等實現類似效果

總結

學習建議

  1. 從相似點開始:Swift 和 Kotlin 有很多相似的概念,可以快速上手
  2. 重點關注差異:特別注意可選類型、內存管理、語法細節的不同
  3. 多寫代碼:理論學習后要多實踐,加深理解
  4. 利用工具:使用 Xcode 的代碼補全和錯誤提示
  5. 閱讀官方文檔:Apple 的 Swift 文檔非常詳細

下一步學習方向

  1. iOS 框架學習:UIKit、SwiftUI、Core Data 等
  2. 架構模式:MVC、MVVM、VIPER 等
  3. 網絡編程:URLSession、Alamofire 等
  4. 數據持久化:Core Data、SQLite、UserDefaults
  5. 測試:XCTest、UI Testing
  6. 性能優化:Instruments、內存管理

常用資源

  • Swift 官方文檔
  • Apple Developer Documentation
  • Swift Playgrounds
  • Hacking with Swift
  • Ray Wenderlich

本指南持續更新中,歡迎反饋和建議!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95893.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95893.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95893.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

嵌入式C語言筆記十七——構造數據類型

一.結構體&#xff1a;1.類型定義&#xff1a;struct 結構體名 {數據類型1 成員變量1;數據類型2 成員變量2;數據類型3 成員變量3;... };struct student {char name[32];char sex;int age;int score; };2.結構體變量定義&#xff1a;存儲類型 數據類型 變量名;3.結構體元素初始化…

深入實踐G1垃圾收集器調優:Java應用性能優化實戰指南

深入實踐G1垃圾收集器調優&#xff1a;Java應用性能優化實戰指南 一、技術背景與應用場景 隨著微服務和海量并發請求的普及&#xff0c;Java應用在生產環境中對低延遲和高吞吐的需求日益顯著。傳統的CMS和Parallel GC 在大內存場景下常出現Full GC 停頓時間長、吞吐下降等問題…

【JobScheduler】Android 后臺任務調度的核心組件指南

JobScheduler 是 Android 平臺上原生支持在直接啟動模式&#xff08;Direct Boot Mode&#xff09;下執行任務的調度器。 相比 WorkManager 需要復雜的配置才能勉強支持直接啟動&#xff0c;JobScheduler 在這方面有著天生的優勢和明確的 API 支持。如果你面臨的硬性要求是必須…

c# 調用basler 相機

目錄 一聯合halcon&#xff1a; 二 c# 原生 一聯合halcon&#xff1a; 環境配置 下載安裝pylon軟件 下載安裝halcon 創建 winform項目 test_basler 添加引用 打開pylon可以連接相機 可以看到我的相機id為23970642 &#xff08; c#聯合halcon的基礎教程&#xff08;案例…

《2025年AI產業發展十大趨勢報告》四十六

《2025年AI產業發展十大趨勢報告》四十六隨著科技的迅猛發展&#xff0c;人工智能&#xff08;AI&#xff09;作為引領新一輪科技革命和產業變革的戰略性技術&#xff0c;正逐步滲透到各個行業和領域&#xff0c;成為推動經濟社會發展的重要引擎。2023年&#xff0c;生成式AI的…

c++ 雜記

1. 為什么返回*this?2. 3. 友元函數的使用&#xff1a;需要頭文件中類內外聲明&#xff0c;cpp文件中實現定義哦// Sales_data.h #ifndef SALES_DATA_H #define SALES_DATA_H#include <string>class Sales_data {std::string bookNo;int units_sold 0;double revenue …

PDF文件基礎-計算機字體

計算機字體的原理包含了字符編碼、字形渲染和字體文件存儲三個關鍵技術。 字符編碼負責將每個字符映射到一個唯一的數字碼&#xff1b;字形渲染則將這些數字碼轉換成屏幕或紙張上可識別的圖形&#xff1b;字體文件存儲則包含了字符的編碼、圖形描述信息以及字體的其他屬性&…

華為IP(9)

OSPF的基本配置OSPF路由計算前言&#xff1a;1)同一區域內的OSPF路由器擁有完全一致的LSDB&#xff0c;在區域內部&#xff0c;OSPF采用SPF算法完成路由計算。2&#xff09;隨著網絡規模不斷擴大&#xff0c;路由器為了完成路由計算所消耗的內存、CPU資源也越來越多。通過區域劃…

java.nio.file.InvalidPathException異常

一.問題概述 本人在ubuntu22.04的操作系統上&#xff0c;運行java程序時創建一個文件時&#xff0c;由于文件名稱中包含了中文&#xff0c;所以導致了程序拋出了java.nio.file.InvalidPathException的異常。 java.nio.file.InvalidPathException: Malformed input or input co…

Next系統總結學習(一)

下面我按題號逐條 詳細 解釋并給出示例與最佳實踐。為便于閱讀&#xff0c;我會同時給出關鍵代碼片段&#xff08;偽代碼/實用例子&#xff09;&#xff0c;并指出常見坑與解決方案。 1. 你是如何理解服務端渲染&#xff08;SSR&#xff09;的&#xff1f;它的核心工作流程是怎…

房屋安全鑒定需要什么條件

房屋安全鑒定需要什么條件&#xff1a;專業流程與必備要素解析房屋安全鑒定是保障建筑使用安全的重要環節&#xff0c;它通過對建筑結構、材料性能及使用狀況的全面評估&#xff0c;為房屋的安全使用、改造或維護提供科學依據。隨著城市建筑老化及自然災害頻發&#xff0c;房屋…

現代C++:現代C++?

C語言正在走向完美&#xff0c;所以&#xff0c;C語言值得學習&#xff08;甚至研究&#xff09;&#xff0c;這些知識可以成為一切編程的基礎。然而在實踐中&#xff0c;不必全面的使用C語言的各種特性&#xff0c;而應根據工程項目的實際情況&#xff0c;適當取舍&#xff08…

【C++】哈希表實現

1. 哈希概念 哈希(hash)又稱散列&#xff0c;是?種組織數據的方式。從譯名來看&#xff0c;有散亂排列的意思。本質就是通過哈希 函數把關鍵字Key跟存儲位置建立一個映射關系&#xff0c;查找時通過這個哈希函數計算出Key存儲的位置&#xff0c;進行快速查找 1.1 直接定址法…

ai 玩游戲 llm玩街霸 大模型玩街霸 (3)

1. 開源代碼地址&#xff1a; https://github.com/OpenGenerativeAI/llm-colosseum 2. 架構&#xff1a; 3. 圖片&#xff1a; 4. 感覺還是下面的步驟&#xff1a; a. 實時理解游戲當前環境&#xff0c;英雄角色&#xff0c;英雄狀態 b. 根據當前狀態感知&#xff0c;生成英雄…

2025年滲透測試面試題總結-59(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 一、SQL注入全解 二、XSS與文件漏洞 三、服務端漏洞專題 四、職業經驗與能力評估 1、注入攻擊原理是什么…

GPT系列--類GPT2源碼剖析

無需多言&#xff0c;大家應該都用過了&#xff0c;如今都更新到GPT-5了。1. GPT-1回到2018年的NLP&#xff0c;神仙打架&#xff0c;BERT與GPT不分先后。GPT是“Generative Pre-Training”的簡稱&#xff0c;生成式的預訓練。BERT和GPT肯定是GPT難訓練&#xff0c;引用量也是B…

這是一款沒有任何限制的免費遠程手機控制手機的軟件

這是一款沒有任何限制的免費遠程手機控制手機的軟件支持安卓和蘋果1.安裝1.1被控制端安裝airdroid1.2控制端air mirror2.登錄賬號控制端和被控制端登錄同一個賬號3.控制打開控制端軟件選擇要控制的機器直接點“遠程控制“

Observability:更智能的告警來了:更快的分診、更清晰的分組和可操作的指導

作者&#xff1a;來自 Elastic Drew Post 探索 Elastic Stack 告警的最新增強功能&#xff0c;包括改進的相關告警分組、將儀表盤鏈接到告警規則&#xff0c;以及將調查指南嵌入到告警中。 在 9.1 版本中&#xff0c;我們對告警進行了重大升級&#xff0c;幫助 SRE 和運維人員更…

數智之光燃盛景 共同富裕創豐饒

8月29日&#xff0c;2025數博會“一帶一路”國際大數據產業發展暨數智賦能新時代、共同富裕向未來的會議在貴陽國際生態會議中心隆重舉行。作為全球大數據領域的重要盛會&#xff0c;此次活動吸引了來自聯合國機構、國際組織、科研院所、知名企業等社會各界的百余位代表&#x…

【網絡編程】recv函數的本質是什么?

一、為什么說recv函數的本質是 “copy”&#xff1f; recv是用于從網絡連接&#xff08;或其他 IO 對象&#xff09;接收數據的函數&#xff0c;它的核心動作不是 “從網絡上拉取數據”&#xff0c;而是 “把已經到達內核緩沖區的數據復制到用戶程序的緩沖區”。 具體流程拆解&…