如何强制结构字段为某种类型?

时间:2013-06-09 16:05:59

标签: racket

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

#lang racket
(struct Car (model year))

我尝试过使用合同(但是因为我是新手,所以这个没有明显起作用......:P)

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

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

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

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

1 个答案:

答案 0 :(得分:6)

我认为你至少打了一个,也许是以下两个:

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

  2. 有一个special form of contracts for structs,您可以在其中为每个字段指定合同。你在上面尝试的只是构造函数的契约。虽然可以成为您想要的,但请考虑使用struct的合同。

  3. 将两者结合起来:

    ;; 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))
    

    P.S。在Racket中的FWIW,常见的样式来大写结构名称 - 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