透明和预制结构有什么区别?

cro*_*oyd 8 racket

正如标题所暗示的,我不明白定义结构时使用#:transparent和使用之间的区别#:prefab.该参考文献提到预制件涉及某种全球共享.

他们之间有什么区别?我应该在哪种情况下使用另一种?

L.Z*_*aki 8

要使结构类型透明,请在字段名称序列后使用#: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.

  • 这个答案可能应该 [link to the docs](http://docs.racket-lang.org/guide/define-struct.html?q=prefab#%28tech._prefab%29) 文本来自哪里。 (3认同)
  • 从某种意义上说,"#:transparent"是不透明和预制之间的"温暖的粥粥".事后看来它应该是默认的,使用`#:opaque`和`#:prefab`修饰符,恕我直言. (2认同)

Lei*_*sen 6

球拍引导可能有一个更温和简介预制结构.

最大的区别是透明结构仍然需要结构构造函数来创建其中一个.

例如,给定以下结构定义:

(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.


stc*_*ang 6

为了扩展其他答案,并为问题的第二部分提供更多示例:

#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)
  • 如果要在没有异常的情况下强制执行struct抽象,则使用opaque结构,即只能使用访问器创建和检查结构.
  • 使用透明结构来访问打印机并且相同?
  • 如果要进行序列化,例如从磁盘写入和读取时,请使用预制结构.


Jac*_*ack 5

尚未提及的另一个重要细节:透明(和正常)结构是生成的。这意味着,如果您两次定义相同的结构,则使用该结构定义的第一个实例创建的值将不会是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)

我认为,仅代表一些汇集在一起​​的原始数据的结构应该是预制的,以获得自由、简单和安全的序列化,对如何构造有限制的结构应该是透明的,并且应该封装一些行为和结构隐藏信息不应该是透明的,也不应该是预制的。这些只是指导方针,但您的里程可能会有所不同。