6

如何强制执行此结构中字段的类型?

#lang racket
(struct Car (model year))

我尝试过使用合同(但由于我是球拍新手,这个显然不起作用......:P)

(provide (contract-out
      [Car (string? integer? . -> . Car?)]))

示例:这成功但它不应该......

(define my-car (Car 2008 "A3"))

可悲的是,它似乎没有写在任何地方如何完成这项工作。

4

1 回答 1

6

我认为您至少达到了一个,也许是以下两个:

  1. 使用(provide (contract-out ....))意味着合同仅适用于模块边界——仅适用于该模块的其他模块require。因此,如果您的测试示例位于同一模块中,则合同将不适用。相反,您可以使用define/contract使合同适用于事物本身,无论是在定义它的模块中,还是在您定义的模块之外provide

  2. s有一种特殊的合同形式,struct您可以在其中为每个字段指定一个合同。您在上面尝试的只是构造函数上的合约。尽管这可能是您想要的,但请考虑使用合同struct代替。

结合两者你可以做:

;; Define the contract on the struct itself.
;; Contract is used even within this module.
(provide car)
(define-struct/contract car ([model string?]
                             [year integer?]))

如果您确实希望合同适用于模块边界,那么您将使用:

;; Define the contract only as `provide`d.
;; Contract is used only for code `require`-ing this module.
(provide (contract-out (struct car ([model string?]
                                    [year integer?]))))
(struct car (model year))

ps FWIW 在 Racket 中的常见样式是将结构名称大写 -car不是Car


更新:只是为了更清楚地说明差异:

#lang racket

(module mod racket
  (provide car0)
  (define-struct/contract car0 ([model string?]
                                [year integer?]))

  (car0 "foo" "bar") ;; gives contract violation
                     ;; because contract on struct itself

  (struct car1 (model year))
  (provide (contract-out (struct car1 ([model string?]
                                       [year integer?]))))

  (car1 "foo" "bar") ;; does NOT give contract violation
                     ;; because contract only on the `provide`
  )

(require 'mod)
(car0 "foo" "bar") ;; gives contract violation
(car1 "foo" "bar") ;; gives contract violation
于 2013-06-09T17:04:55.067 回答