2011-07-06 43 views
7

printf,fprintf等:全部接受%a转换。OCaml中的用户定义打印机

的手册%a说:

“用户定义的打印机采用两个参数,并应用第一个outchan中(电流输出信道)和第二个参数因此,第一个参数必须具备的。输入out_channel - >'b - >单元,然后输入第二个'b',函数产生的输出因此会插入当前点的fprintf输出中。“

我无法理解用户定义的打印机的用途以及如何实现和使用它。有人可以解释动机并提供一个例子吗?例如,当你想要打印一个复杂的数据结构时,为什么不能直接将自定义函数的数据结构打印到字符串或输出?

+0

'sprintf'和'ksprintf'采取单位的'功能 - >“A - >字符串不像你提到的功能。 – nlucaroni

+0

我的问题可能很不精确。我想知道的是,在什么情况下,人们应该更喜欢使用'%a'而不是仅仅打印到一个字符串(使用'printf'和'%s'或'sprintf'或'ksprintf'等)并且然后使用该字符串执行其他操作 - 例如在通道上输出。 – ndbd

回答

2

如果你有一个函数TY-> string,你可以用它来与"%s"打印您的数据,所以我觉得在现实的情况下,你可以“只打印你的数据结构”。代替使用"%a"可能是一种风格选择。它在某些方面似乎更加一致。

在32位系统上,字符串长度限制在16MB左右。所以你可以想象一下"%a"会工作而"%s"会失败的情况:如果中间字符串比这个更长。不过,我从来没有在实践中出现这种情况。我自己就用"%s"

5

你是什么意思的“只是打印复杂的数据结构”?一旦你定义了一个将你的数据结构转换为字符串的函数,你可以这样做。也可以用“默认表示”(参见http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=139)“转储”数据结构,但这比调试更重要。

说了这么多;为%a一个很简单的例子:

type ty = A | B 

let ty_to_string = function 
    | A -> "A" 
    | B -> "B" 

let print_ty chan v = output_string chan (ty_to_string v) 

let _ = Printf.printf "%a" print_ty A 
+0

我不理解的是为什么人们更喜欢这个,比如说 让_ = Printf.printf“%s”(ty_to_string A)或 让_ = Printf.fprintf stdout“%s”(ty_to_string A)。至少后者给出了某种抽象方法来打印哪个通道,类似于在上面的例子中使用%a? – ndbd

+2

事情是,对于较大的结构转换为字符串可能是昂贵的(想想:字符串连接)。如果可能的话,直接写入频道会更有效率。当你有这样的功能时,'%a'自然就会出现。 – akoprowski

1

使用%a可以让打印直接进入输出通道,而不是“%s”并将要打印的值串化并打印出来。

这种区别看起来完全是效率问题 - 为什么当将串行化数据直接发送到输出通道是可能和合理的时候,为什么要分配一个潜在的大字符串(或者使用缓冲区,并进行指数大小调整和复制) ? Jeffrey非常正确地指出,由于字符串长度的原因,非常大的串行化可能会在32位系统上失败。

我用%a常常在我的代码,使用电池组合的打印功能来创建自定义打印机对我的价值观:

let range_print oc r = 
    let print_one oc (a,b) = fprintf oc "%d:%d" a b in 
    List.print ~first:"" ~last:"" ~sep:"," print_one oc r 
let print_rule print_pred print_dec oc r = 
    fprintf oc "%a,%a" print_pred r.pred print_dec r.dec 
let print_item oc x = print_rule range_print Int.print oc x in 
... 
printf "IN : %a\nOUT: %a\n" print_item a print_item b;