F#中的printfn类型,静态与动态字符串 [英] Type of printfn in F#, static vs dynamic string
问题描述
我刚开始在Mono中玩F#,出现了我无法完全理解的以下问题.在printfn
和TextWriterFormat
上查找信息也没有启发,所以我想在这里问.
I just began toying around with F# in Mono and the following problem arose that I cannot quite understand. Looking up information on printfn
and TextWriterFormat
didn't bring enlightenment either, so I thought I'm going to ask here.
在FSI中,我运行以下命令:
In FSI I run the following:
> "hello";;
val it : string = "hello"
> printfn "hello";;
hello
val it : unit = ()
只需一个普通的字符串并打印即可.美好的.现在,我想声明一个包含相同字符串的变量并打印出来:
Just a normal string and printing it. Fine. Now I wanted to declare a variable to contain that same string and print it as well:
> let v = "hello" in printfn v ;;
let v = "hello" in printfn v ;;
---------------------------^
\...\stdin(22,28): error FS0001: The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>'
根据我的阅读,我了解到printfn
需要一个常量字符串.我也了解我可以使用printfn "%s" v
之类的方法来解决此问题.
I understood from my reading that printfn
requires a constant string. I also understand that I can get around this problem with something like printfn "%s" v
.
但是,我想了解此处键入的内容.显然,"hello"
的类型与string
相同.那为什么会有类型问题呢? printfn
有什么特别的地方吗?据我了解,编译器已经在第一个字符串的参数上执行类型检查,以致printfn "%s" 1
失败.静态情况.
However, I'd like to understand what's going on with the typing here. Clearly, "hello"
is of type string
as well as v
is. Why is there a type problem then? Is printfn
something special? As I understand it the compiler already performs type-checking on the arguments of the first string, such that printfn "%s" 1
fails.. this could of course not work with dynamic strings, but I assumed that to be a mere convenience from the compiler-side for the static case.
推荐答案
好问题.如果查看printfn
的类型,即Printf.TextWriterFormat<'a> -> 'a
,则会看到编译器在编译时自动将字符串强制为TextWriterFormat
对象,从而推断出适当的类型参数'a
.如果要对动态字符串使用printfn
,则可以自己执行该转换:
Good question. If you look at the type of printfn
, which is Printf.TextWriterFormat<'a> -> 'a
, you'll see that the compiler automatically coerces strings into TextWriterFormat
objects at compile time, inferring the appropriate type parameter 'a
. If you want to use printfn
with a dynamic string, you can just perform that conversion yourself:
let s = Printf.TextWriterFormat<unit>("hello")
printfn s
let s' = Printf.TextWriterFormat<int -> unit>("Here's an integer: %i")
printfn s' 10
let s'' = Printf.TextWriterFormat<float -> bool -> unit>("Float: %f; Bool: %b")
printfn s'' 1.0 true
如果该字符串是静态已知的(如上述示例所示),那么您仍然可以让编译器将正确的泛型参数推断为TextWriterFormat
,而不是调用构造函数:
If the string is statically known (as in the above examples), then you can still have the compiler infer the right generic argument to TextWriterFormat
rather than calling the constructor:
let (s:Printf.TextWriterFormat<_>) = "hello"
let (s':Printf.TextWriterFormat<_>) = "Here's an integer: %i"
let (s'':Printf.TextWriterFormat<_>) = "Float: %f; Bool: %b"
如果字符串真正是动态的(例如,它是从文件中读取的),那么您将需要显式地使用类型参数并像前面的示例中一样调用构造函数.
If the string is truly dynamic (e.g. it's read from a file), then you'll need to explicitly use the type parameters and call the constructor as I did in the previous examples.
这篇关于F#中的printfn类型,静态与动态字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!