正如标题所暗示的,我不明白定义结构时使用#:transparent和使用之间的区别#:prefab.该参考文献提到预制件涉及某种全球共享.
他们之间有什么区别?我应该在哪种情况下使用另一种?
要使结构类型透明,请在字段名称序列后使用#:transparent关键字:
(struct posn (x y)
#:transparent)
> (posn 1 2)
(posn 1 2)
Run Code Online (Sandbox Code Playgroud)
透明结构类型的实例打印类似于对构造函数的调用,因此它显示结构字段值.透明结构类型还允许反射操作,例如struct?和struct-info,用于其实例.
尽管透明结构类型以显示其内容的方式打印,但是与数字,字符串,符号或列表的打印形式不同,结构的打印形式不能用于表达式以使结构返回.
预制("先前制造的")结构类型是Racket打印机和表达式读取器已知的内置类型.存在无限多个这样的类型,并且它们通过名称,字段计数,超类型和其他此类细节来索引.预制结构的打印形式类似于矢量,但它以#s而不是#开头,而打印形式的第一个元素是预制结构类型的名称.
最后,我认为您可能需要使用#:透明大部分时间而不是#:prefab,根据我的经验,我通常使用#:transparent.
该球拍引导可能有一个更温和简介预制结构.
最大的区别是透明结构仍然需要结构构造函数来创建其中一个.
例如,给定以下结构定义:
(struct foo (a b) #:prefab)
Run Code Online (Sandbox Code Playgroud)
以下是创建完全相同结构的两种方法.
> (foo 1 2)
'#s(foo 1 2)
> #s(foo 1 2)
'#s(foo 1 2)
Run Code Online (Sandbox Code Playgroud)
这意味着任何球拍模块都可以创建foo预制结构,即使没有首先定义它.如果您想将其放在宏中,或者将其发送到在不同计算机上运行的单独的球拍实例,这将非常有用.
一般来说,我建议使用#:transparent结构,除非你需要结构的全部功能#:prefab.
为了扩展其他答案,并为问题的第二部分提供更多示例:
#lang racket
(struct A (x y))
(displayln (A 1 2)) ; => #<A>
(equal? (A 1 2) (A 1 2)) ; => #f
;(equal? (A 1 2) (read (open-input-string (~a (A 1 2))))) ; => ERR: bad syntax
(struct B (x y) #:transparent)
(displayln (B 3 4)) ; => #(struct:B 3 4)
(equal? (B 3 4) (B 3 4)) ; => #t
(equal? (B 3 4) (read (open-input-string (~a (B 3 4))))) ; => #f
(struct C (x y) #:prefab)
(displayln (C 5 6)) ; => #s(C 5 6)
(equal? (C 5 6) (C 5 6)) ; => #t
(equal? (C 5 6) (read (open-input-string (~a (C 5 6))))) ; => #t
Run Code Online (Sandbox Code Playgroud)
尚未提及的另一个重要细节:透明(和正常)结构是生成的。这意味着,如果您两次定义相同的结构,则使用该结构定义的第一个实例创建的值将不会是equal?使用第二个定义创建的值。您可以在 REPL 会话中亲自看到这一点:
> (struct posn (x y) #:transparent)
> (define origin1 (posn 0 0))
> (struct posn (x y) #:transparent)
> (define origin2 (posn 0 0))
> (equal? origin1 origin2)
#f
Run Code Online (Sandbox Code Playgroud)
尽管定义相同且内容相同,但这两个实例却不同equal?。尽管结构是透明的,但由于Leif Anderson 指出的原因,它们被视为单独的定义,仅使用 #:transparent 仍然要求创建结构的唯一方法是使用结构形式定义的构造函数。两个定义意味着两个不同的构造函数。
然而,使用预制结构,这种限制就消失了 - 您可以通过编写它们的阅读器形式来自己创建预制结构,例如#s(posn 0 0). 不再有理由要求使用其定义的构造函数创建结构的所有实例,因此两个不同但相同的结构定义没有理由不能相互识别:
> (struct posn (x y) #:prefab)
> (define origin1 (posn 0 0))
> (struct posn (x y) #:prefab)
> (define origin2 (posn 0 0))
> (equal? origin1 origin2)
#t
> (equal? origin1 #s(posn 0 0))
#t
Run Code Online (Sandbox Code Playgroud)
我认为,仅代表一些汇集在一起的原始数据的结构应该是预制的,以获得自由、简单和安全的序列化,对如何构造有限制的结构应该是透明的,并且应该封装一些行为和结构隐藏信息不应该是透明的,也不应该是预制的。这些只是指导方针,但您的里程可能会有所不同。