似乎sprintf
在其格式说明符中不允许%a
。这是正确的吗?如果是这样,为什么会这样,是否有解决方法?
示例。我有一个冗长而复杂的数据类型:
type t = Foo | Baz
我有一个这种类型的漂亮打印机,它将其值的字符串表示形式发送到任意out_channel
:
let pp_t oc = function
| Foo -> fprintf oc "Foo"
| Baz -> fprintf oc "Baz"
如果我再写
let _ = printf "%a=%d" pp_t Foo 2
或
let _ = eprintf "%a=%d" pp_t Foo 2
然后一切正常 - 消息" Foo = 2"按预期结束我的stdout或我的stderr。但如果我写
let s = sprintf "%a=%d" pp_t Foo 2
然后我收到编译错误,抱怨参数pp_t
的类型为out_channel -> t -> unit
,但表达式的类型为unit -> 'a -> string
。
是否根本无法在%a
的格式说明符中使用sprintf
?
答案 0 :(得分:3)
使用Format
模块进行漂亮的打印,使用Format.asprintf
函数代替sprintf
来构造字符串(我通常只在文件的开头做open Format
)
可以将%a
转化规范与sprintf
一起使用。但是,所需函数的类型与Printf.fprintf
和Printf.printf
所需的类型不同。
所有漂亮的打印机(满足%a
转换所需的值类型的函数)会对其类型中的输出类型进行编码。因此,对于printf
函数的不同系列,您需要使用不同的漂亮打印功能。
对于Format
模块漂亮打印机,您需要一个类型为formatter -> 'a -> unit
的函数。这是顶级和调试器也需要的类型,它也是一种最常见的漂亮打印功能(像Core这样的库,以及许多其他库,提供满足的漂亮打印机)这个签名)。 Format
模块还提供asprintf
函数,与sprintf
函数不同,它与%a
转换效果很好(即它具有相同的formatter -> 'a -> unit
类型)。
在Printf.printf
的情况下,漂亮打印机的类型应为out_channel -> 'a -> unit
。这种类型的通用性要低得多,因此不如格式的那么流行。很少有图书馆提供一个。
最后,Printf.sprintf
函数需要类型为unit -> 'a -> string
的打印机。通常,获得这样漂亮的打印机的唯一方法是手动编写它(有时使用Printf.asprintf
)。在你的情况下,它将是:
let pp_t () = function
| Foo -> "Foo"
| Baz -> "Baz"
答案 1 :(得分:2)
为了摆脱格式化功能中显示的特定数据类型,您应该始终使用Format
模块并为具有签名val pp_t : Format.formatter -> t -> unit
的类型设计漂亮的打印机;这也是toplevel要求为您的数据类型安装#install_printer
的自定义打印机的签名。
配备此功能后,您只需将Format.asprintf
与"%a"
一起使用。