在python对象中,重写对象的方法__repr__
和__str__
可以分别提供对象的“明确”表示和“人类可读”表示。如何在球拍中实现类似的行为?
我遇到了printable<%>
界面here,这似乎应该可以用于此目的,但是我还无法使其完全正常地工作。以文档中的标准“鱼”示例为基础:
(define fish%
(class* object% (printable<%>)
(init size) ; initialization argument
(super-new) ; superclass initialization
;; Field
(define current-size size)
;; Public methods
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size)))
;; implement printable interface
(define/public (custom-print port quoting-depth)
(print "Print called!"))
(define/public (custom-write port)
(print "Write called!"))
(define/public (custom-display port)
(print "Display called!"))))
这是我得到的输出:
> (define f (new fish% [size 10]))
> f
"Display called!""Display called!""Print called!"
> (print f)
"Write called!""Print called!"
> (display f)
"Display called!""Display called!"
> (write f)
"Write called!""Write called!"
>
所以问题是三个方面:
为什么会这样运行,即在对象看起来很单一的情况下调用多个方法?
custom-print,custom-write和custom-display方法应评估什么?他们应该只是返回一个字符串,还是应该视情况实际带来打印,书写或显示的副作用?例如。自定义写入方法应该在内部调用write
函数吗?
这完全是用于此目的的正确结构吗?如果没有,那是什么/是什么?
答案 0 :(得分:1)
至
- 为什么它会以这种方式运行,即在对象看起来很单一的情况下调用多个方法?
您不小心在print
中使用了write
,因此写入值将首先打印该值。
(define/public (custom-write port)
(print "Write called!"))
display
中也存在类似的问题。
还请记住打印/写入/显示到正确的端口。
尝试
#lang racket
(define fish%
(class* object% (printable<%>)
(init size) ; initialization argument
(super-new) ; superclass initialization
;; Field
(define current-size size)
;; Public methods
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size)))
;; implement printable interface
(define/public (custom-print port quoting-depth)
(print (~a "Print " current-size "\n") port))
(define/public (custom-write port)
(write (~a "Write " current-size "\n") port))
(define/public (custom-display port)
(display (~a "Display " current-size "\n") port))))
在REPL中,您将看到:
> (define f (new fish% [size 10]))
> f
"Print 10\n"
> (display f)
Display 10
> (write f)
"Write 10\n"
答案 1 :(得分:1)
另一个答案已经帮助您在代码中发现问题-您需要使用给定的端口作为参数,而不是隐式(current-output-port)
-但解释并不正确。以相反的顺序解决您的问题:
- 这完全是用于此目的的正确结构吗?如果没有,那是/它是什么?
是的,printable<%>
是用于自定义基于类的对象的打印的正确结构。更一般而言,不是类的结构类型可以通过gen:custom-write
通用接口或用于实现prop:custom-write
的低级printable<%>
结构类型属性来自定义打印。
- custom-print,custom-write和custom-display方法应评估什么?他们应该只是返回一个字符串,还是应该视情况实际带来打印,书写或显示的副作用?例如。 custom-write方法应该在内部调用write函数吗?
这些方法实际上应该在它们作为参数给出的端口上执行IO的副作用。他们应在内部使用相应的功能(例如,write
使用custom-write
,print
使用custom-print
)以递归方式打印/写入/显示字段中的值。另一方面,当直接发出特定字符时,它们通常应使用诸如write-char
,write-string
或printf
之类的功能。 The docs for gen:custom-write
给出了一个打印为<1, 2, "a">
的元组数据类型的示例:它对尖括号和逗号使用write-string
,但是递归print
/ write
/ display
表示元组的元素。
- 为什么它会以这种方式运行,即在对象看起来很单一的情况下调用多个方法?
这是您问题中涉及最多的部分。可通过多个挂钩自定义在Racket中进行打印:有关一些示例,请参见current-print
,port-write-handler
,global-port-print-handler
和make-tentative-pretty-print-output-port
。这些定制挂钩中有许多在产生输出的过程中使用中间端口。
不是 解释的一件事是您在实现中使用了print
,特别是因为print
被绑定到了普通的Racket函数,词法范围,而不是对象的方法。
作为说明,请考虑您的示例的以下修改,该示例向(current-output-port)
报告作为该方法的参数给出的端口的标识:
#lang racket
(define report
(let ([next-id 0]
[id-cache (make-hash)])
(λ (op port)
(printf "~a ~a ~v\n"
op
(hash-ref id-cache
port
(λ ()
(define id next-id)
(hash-set! id-cache port id)
(set! next-id (add1 next-id))
id))
port))))
(define fish%
(class* object% (printable<%>)
(super-new)
;; implement printable interface
(define/public (custom-print port quoting-depth)
(report "custom-print " port))
(define/public (custom-write port)
(report "custom-write " port))
(define/public (custom-display port)
(report "custom-display" port))))
(define f (new fish%))
f
(print f)
(newline)
(display f)
(newline)
(write f)
在DrRacket中,这将生成输出:
custom-display 0 #<output-port:null>
custom-display 1 #<output-port:null>
custom-print 2 #<printing-port>
custom-display 3 #<output-port:null>
custom-display 4 #<output-port:null>
custom-print 5 #<printing-port>
custom-display 6 #<output-port:null>
custom-display 7 #<printing-port>
custom-display 8 #<output-port:null>
custom-write 9 #<printing-port>
在命令行中,输出为:
$ racket demo.rkt
custom-write 0 #<output-port:null>
custom-print 1 #<output-port:redirect>
custom-write 2 #<output-port:null>
custom-print 3 #<output-port:redirect>
custom-display 4 #<output-port:null>
custom-display 5 #<output-port:redirect>
custom-write 6 #<output-port:null>
custom-write 7 #<output-port:redirect>