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

Tes*_*esX 6 racket

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

#lang racket
(struct Car (model year))
Run Code Online (Sandbox Code Playgroud)

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

(provide (contract-out
      [Car (string? integer? . -> . Car?)]))
Run Code Online (Sandbox Code Playgroud)

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

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

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

Gre*_*ott 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?]))
Run Code Online (Sandbox Code Playgroud)

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

;; 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))
Run Code Online (Sandbox Code Playgroud)

ps在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
Run Code Online (Sandbox Code Playgroud)