4.13动态绑定:parameterize

parametterize形式在它方法体执行中关联了一个值到固定参数。

  (parameterize ([parameter-expr value-expr] ...)
    body ...+)

术语“参数化”有时候被用来指函数的参数,但是在Racket里面有特殊含义。

比如,参数error-print-width指定了在错误信息里有多少字符会被打印。
更一般的情况下,参数化实现了一种动态的绑定。函数make-parameter接受一个值并把它赋值给一个参数。像函数一样调用一个参数将返回它的当前值。

  >(define location (make-parameter "here"))
  >(location)
  "here"

每个parameter-expr必须产生一个参数。在执行的方法体中,每个指定的参数都已经被初始化相应的value-expr的值。当离开parameterize形式,不管是return,exception,或者其它逃逸,参数都会恢复成之前的值。
parameterize在整个方法体执行期间都会调整参数值,即使在方法体之外定义的parameterize,对内部也有影响。

  >(define (would-you-could-you?)
      (and (not (equal? (location) "here"))
           (not (equal? (loaction) "there"))))  
  >(would-you-could-you?)
  #f
  >(parameterize ([location "on a bus"])
        (would-you-could-you?))
  #t

如果在parameterize定义内部定义的时候没有执行的表达式,当它在外部执行时,它将无法使用parameterize定义的值。
给参数的函数传递一个值,将给参数重新赋值。
使用parameterize更适合用来更新一个参数值,基于相同的理由set!更适合用来更新一个变量。
使用set!也可以解决parameterize的问题。例如

  >(define lokation "here")
  >(define (would-ya-could-ya?)
        (and (not (equal? lokation "here"))
               (not (equal? lokation "there"))))
  >(set! lokation "on a bus")
  >(would-ya-could-ya?)
  #t

但是parameterize有几个重要区别

  • parameterize在操作逃逸到异常时,可以自动重置值。但是在异常处理后其它形式里回溯set!值很麻烦。

  • 参数化可以很好的和尾调用协同工作。

  • 参数化可以在线程中使用。parameterize只会调整当前线程的值,可以避免和其它线程发生冲突。

推荐阅读更多精彩内容