Skip to content

错误处理 ​

实现状态: try / catch / throw / try? / try! / Result<T, E> 已实现;throws T typed throws 部分实现;rethrows 未实现

SYX 提供三种错误传播路径:

  1. throws / try — 异常抛出与捕获(运行时错误)
  2. Result<T, E> — 显式代数类型
  3. Optional — 用 nil 表示失败(最轻量)

本章覆盖语法、用法、Result 集成与跨函数传播。

try / catch 块 ​

swift
import System

func main() {
    do {
        let content = File.read("/tmp/x")
        print(content)
    } catch (err) {
        print("failed: \(err)")
    }
}
  • do { } 块内可 throw / 调 throws 函数
  • 异常触发后立即跳到 catch,跳过 try 块剩余部分
  • err 类型 MVP 是 String(更复杂错误类型规划中)

来源:crates/syx-driver/tests/fixtures/lsp/result_generic.sy

跨函数 try(R-38 output 钉 · SEM-THROW) ​

do { try g() } catch 必须进入 catch(错误不得当普通值打印):

swift,output
// prints: caught
enum E: Error {
    case bad
}

func g() throws {
    throw E.bad
}

func main() {
    do {
        try g()
        print("value")
    } catch {
        print("caught")
    }
}

throw 表达式 ​

swift
func divide(_ a: Int, _ b: Int) throws -> Int {
    if (b == 0) {
        throw "division by zero"
    }
    return a / b
}
  • throw expr 抛 expr(MVP 类型 String)
  • 仅在 throws 函数内合法
  • 抛 String / Result.err / 自定义 enum 都允许(expr 类型由函数签名的 throws T 决定)

throws 函数声明 ​

swift
import System

func loadFile(path: String) throws -> String {
    if (!File.exists(path)) {
        throw "not found: \(path)"
    }
    return File.read(path)
}

func parseInt(s: String) throws -> Int {
    if (s.count == 0) {
        throw "empty"
    }
    return 0
}
签名含义
throws -> T可能抛出,调用方需 try
throws E -> Ttyped throws(部分实现)抛 E
async throws -> Tasync 且 throws

try 表达式 ​

调用 throws 函数的三种形式:

try expr(必须 try) ​

swift
import System

func loadFile(path: String) throws -> String {
    if (!File.exists(path)) { throw "not found" }
    return File.read(path)
}

func main() {
    let s = try loadFile(path: "/tmp/x")  // String
    print(s)
}
  • 必须用 try 包裹(编译器提示 P001 包装缺失)
  • 等价于 do { let s = loadFile(...) }

try? expr(失败转 nil) ​

swift
import System

func loadFile(path: String) throws -> String {
    if (!File.exists(path)) { throw "not found" }
    return File.read(path)
}

func main() {
    let s = try? loadFile(path: "/tmp/x") // String?
    print(s)
}
  • 成功 → 返回 T
  • 失败 → 返回 nil(异常被吞掉)

try! expr(强制无错) ​

swift
import System

func loadFile(path: String) throws -> String {
    if (!File.exists(path)) { throw "not found" }
    return File.read(path)
}

func main() {
    let s = try! loadFile(path: "/tmp/x") // String
    print(s)
}
  • 成功 → 返回 T
  • 失败 → 运行时 panic

try? 链: 多个 try? 可链式:try? foo() + try? bar(),任一失败 → 整体 nil(视具体语义)。

链式 catch ​

text
do {
    let r = Http.get(url)
    print(r)
} catch (err) where (err.hasPrefix("5")) {
    print("server error: \(err)")
} catch (err) where (err.hasPrefix("4")) {
    print("client error: \(err)")
} catch (err) {
    print("other: \(err)")
}

where 守卫: 早期版本支持 try-catch 块的 where 守卫(部分实现);推荐直接调 try? / switch Result。

Result 类型 ​

Result<T, E> 是显式错误类型的标准方案(第 9 章 枚举):

swift
func parse(s: String) -> Result<String, String> {
    if (s.isEmpty) { return Result.err(value: "empty") }
    return Result.ok(value: s)
}

func main() {
    let r = parse(s: "hello")
    if (Result.isOk(result: r)) {
        print("ok")
    } else {
        print("err")
    }
}

Result 静态构造 ​

Result.ok(value:) / Result.err(value:) 是 String 型 MVP 构造(packages/core/builtins/algebraic/result.sy):

swift
func main() {
    let r1 = Result.ok(value: "42")          // Result<String, String> 成功
    let r2 = Result.err(value: "oops")       // Result<String, String> 失败
    print(Result.isOk(result: r1))
    print(Result.isErr(result: r2))
}

Result 链式 ​

薄 MVP 检查面(完整 .map / .flatMap 泛型仍属加深轨):

swift
func main() {
    let r1 = Result.ok(value: "10")
    print(Result.isOk(result: r1))           // true
    let r2 = Result.err(value: "neg")
    print(Result.isErr(result: r2))          // true
}

方法: Result.ok / Result.err / Result.isOk / Result.isErr / .description 在 packages/core/builtins/algebraic/result.sy。泛型 .map / .flatMap 仍属加深轨。

@Codable + Result 序列化 ​

swift
@Codable
enum ApiError: Error {
    case notFound
    case serverError(Int, String)
}

来源:fixtures/lsp/result_generic.sy · fixtures/lsp/result_generic.sy

throws 与 actor ​

actor 内的 throws func 自动隔离:

swift
import System

actor FileManager {
    func read(path: String) throws -> String {
        if (!File.exists(path)) { throw "not found" }
        return File.read(path)
    }
}

async func main() {
    let m = FileManager()
    do {
        let s = await m.read(path: "/tmp/x")
        print(s)
    } catch (err) {
        print("failed: \(err)")
    }
}

错误处理策略选择 ​

场景选
必须处理的运行时错误(IO、网络)throws + try / catch
可恢复的逻辑错误(解析、转换)Result<T, E>
「有/无」二态(查找、缓存命中)Optional<T>
库内部 panic 路径try! / fatalError
错误类型需要携带多字段enum + Result / typed throws

完整示例 ​

text
enum MathError {
    case divideByZero
    case overflow
}

func safeDivide(_ a: Int, _ b: Int) -> Result&lt;Int, MathError&gt; {
    if (b == 0) { return .err(.divideByZero) }
    if (a > 1000) { return .err(.overflow) }
    return .ok(a / b)
}

func doubleAndPrint(_ a: Int, _ b: Int) {
    switch (safeDivide(a, b)) {
    case .ok(let n) {
        print("\(a) / \(b) = \(n * 2)")
    }
    case .err(.divideByZero) {
        print("oops: divide by zero")
    }
    case .err(.overflow) {
        print("oops: overflow")
    }
    }
}

func main() {
    doubleAndPrint(10, 2)                  // "10 / 2 = 10"
    doubleAndPrint(10, 0)                  // "oops: divide by zero"
    doubleAndPrint(2000, 5)                // "oops: overflow"
}

与 Swift 风格对照 ​

SwiftSYX
do { try … } catch { }do { } catch { }(无 do)
Error 协议MVP 用 String / Result
throws E typed throws部分实现
try? try!已实现
rethrows未实现
Result<T, E> stdlib已实现(含静态 ok / err)
error: { } 闭包参数catch (err) { } 块
try? foo()?.bar()合法

诊断 ​

代码触发修复
S020非 throws 函数内 throw加 throws
P001调 throws 函数未 try加 try / try? / try!
R007try! 失败改 try? / do { } catch
S004throws 类型不匹配修正 throws T

下一章 → 并发

参见 → 语言参考:语句 · 语言参考:声明 · 第 9 章 枚举 · 第 18 章 并发

SYX · Apache-2.0