什么是印读一致性?
What is print-read consistency?
在定义 print-object
方法时它有多重要?
例如,在我看来,SBCL 中的 hash-table
个实例违反了这一原则。
Print-read 一致性表示,在 CL 中,如果 *print-readably*
为真,则打印对象应该:
- 生成打印表示,当使用有效的标准可读表读取时,它与对象相似;
- 或发出类型为
print-not-readable
的错误信号。
相似性 的定义稍微复杂一些,因为它不一定能在单个图像中定义,因为它的全部目的是允许打印对象,然后再读取在另一张图片中。它在3.2.4.2 of the spec, although all of 3.2.4中的定义值得一读。特别注意允许实现扩展相似性的定义。
请注意,我上面的定义中存在一些缺陷:特别是我认为其他打印机和 reader 控制变量需要具有 *print-readably*
的标准值才有意义(例如 *package*
、*read-default-float-format*
等等。with-standard-io-syntax
这里是你想要的工具。
最后请注意,在某些情况下,相似性是针对同一实现 的多个图像定义的。对于标准未定义其可读打印表示的对象,允许实现打印内容,以便 自身 的另一个实例可以重建类似的对象:它不必确保其他实现可以。
这意味着如果您要定义一种打印对象的机制,那么如果 *print-readably*
为真,它应该以读取类似对象的方式打印对象 (也许在同一个实现中),或者发出适当的错误信号:它应该 而不是 做的是以一种不可读的方式悄悄地打印对象,或者以一种读取表示不会 return 一个相似的对象。这样做的一个好方法是使用 print-unreadable-object
,其全部目的是为您确保这一点。
散列表可能可打印也可能不可读。在 SBCL 中,它们是:
* (defvar *h* (make-hash-table))
*h*
* (setf (gethash 'foo *h*) 1)
1
* *h*
#<hash-table :TEST eql :COUNT 1 {1002CE5863}>
* (with-standard-io-syntax (print *h*))
#.(SB-IMPL::%STUFF-HASH-TABLE (MAKE-HASH-TABLE) (QUOTE ((FOO . 1))))
#<hash-table :TEST eql :COUNT 1 {1002CE5863}>
#.(...)
形式将在 SBCL 中读取时重新创建一个类似的哈希表(但仅在 SBCL 中)。
在另一个实现 (Clozure CL) 中,哈希表不可读地打印:
? (defvar *h* (make-hash-table))
*h*
? (setf (gethash 'foo *h*) 1)
1
? *h*
#<hash-table :test eql size 1/60 #x3020012A119D>
? (with-standard-io-syntax (print *h*))
> Error: Attempt to print object #<HASH-TABLE :TEST EQL size 1/60 #x3020012A119D> on stream #<SYNONYM-STREAM to *TERMINAL-IO* #x302000B9DC1D>
在定义 print-object
方法时它有多重要?
例如,在我看来,SBCL 中的 hash-table
个实例违反了这一原则。
Print-read 一致性表示,在 CL 中,如果 *print-readably*
为真,则打印对象应该:
- 生成打印表示,当使用有效的标准可读表读取时,它与对象相似;
- 或发出类型为
print-not-readable
的错误信号。
相似性 的定义稍微复杂一些,因为它不一定能在单个图像中定义,因为它的全部目的是允许打印对象,然后再读取在另一张图片中。它在3.2.4.2 of the spec, although all of 3.2.4中的定义值得一读。特别注意允许实现扩展相似性的定义。
请注意,我上面的定义中存在一些缺陷:特别是我认为其他打印机和 reader 控制变量需要具有 *print-readably*
的标准值才有意义(例如 *package*
、*read-default-float-format*
等等。with-standard-io-syntax
这里是你想要的工具。
最后请注意,在某些情况下,相似性是针对同一实现 的多个图像定义的。对于标准未定义其可读打印表示的对象,允许实现打印内容,以便 自身 的另一个实例可以重建类似的对象:它不必确保其他实现可以。
这意味着如果您要定义一种打印对象的机制,那么如果 *print-readably*
为真,它应该以读取类似对象的方式打印对象 (也许在同一个实现中),或者发出适当的错误信号:它应该 而不是 做的是以一种不可读的方式悄悄地打印对象,或者以一种读取表示不会 return 一个相似的对象。这样做的一个好方法是使用 print-unreadable-object
,其全部目的是为您确保这一点。
散列表可能可打印也可能不可读。在 SBCL 中,它们是:
* (defvar *h* (make-hash-table))
*h*
* (setf (gethash 'foo *h*) 1)
1
* *h*
#<hash-table :TEST eql :COUNT 1 {1002CE5863}>
* (with-standard-io-syntax (print *h*))
#.(SB-IMPL::%STUFF-HASH-TABLE (MAKE-HASH-TABLE) (QUOTE ((FOO . 1))))
#<hash-table :TEST eql :COUNT 1 {1002CE5863}>
#.(...)
形式将在 SBCL 中读取时重新创建一个类似的哈希表(但仅在 SBCL 中)。
在另一个实现 (Clozure CL) 中,哈希表不可读地打印:
? (defvar *h* (make-hash-table))
*h*
? (setf (gethash 'foo *h*) 1)
1
? *h*
#<hash-table :test eql size 1/60 #x3020012A119D>
? (with-standard-io-syntax (print *h*))
> Error: Attempt to print object #<HASH-TABLE :TEST EQL size 1/60 #x3020012A119D> on stream #<SYNONYM-STREAM to *TERMINAL-IO* #x302000B9DC1D>