Racket 编程

2 部分 · 高级特性

异常与契约

异常与契约

使用异常处理运行时错误,用契约系统保障接口的正确使用。

异常处理

#lang racket

;; 抛出异常
(define (divide a b)
  (if (= b 0)
      (error 'divide "division by zero")
      (/ a b)))

;; 捕获异常
(with-handlers ([exn:fail? (lambda (e)
                             (displayln (exn-message e))
                             0)])
  (divide 10 0))  ; 打印错误信息,返回 0

自定义异常

(struct exn:fail:user exn:fail (username))

(define (login name password)
  (unless (valid? name password)
    (raise (exn:fail:user
            "Invalid credentials"
            (current-continuation-marks)
            name))))

契约系统

契约为模块接口添加运行时检查:

#lang racket

(provide
 (contract-out
  [interest-rate (-> number? number?)]))

(define (interest-rate amount)
  (cond
    [(< amount 1000) 0.02]
    [(< amount 10000) 0.03]
    [else 0.04]))

常用契约

(-> number? number? number?)           ; 两数返回一数
(-> string? (listof string?) boolean?) ; 字符串 + 字符串列表 → 布尔
(-> any/c integer?)                     ; 任意输入 → 整数
(->/c [positive?])                      ; 返回值为正数

小结

异常处理运行时错误,契约在模块边界强制执行类型约束。两者结合让你的程序更加健壮。