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 つ、場合によっては両方にヒットしていると思います。

  1. Using(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 一般的なスタイルは、構造体名を大文字にしない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 に答える