我已经在C#中完成了大部分开发工作,并且正在学习F#。这是我想在C#中做的事情:
string AddChars(char char1, char char2) => char1.ToString() + char2.ToString();
编辑:在C#示例中添加了ToString()
方法。
我想用F#编写相同的方法,除此之外我不知道该怎么做:
let addChars char1 char2 = Char.ToString(char1) + Char.ToString(char2)
是否有一种方法可以将这些char
连接到一个string
而不先将它们都转换成string
?
旁注:
我还考虑过制作一个char
数组并将其转换为string
,但这似乎也很浪费。
let addChars (char1:char) (char2: char) = string([|char1; char2|])
答案 0 :(得分:7)
正如我在评论中所说,您的C#代码不会做您想要的事情(即,将字符连接成字符串)。在C#中,添加char
和char
将得到int
。这样做的原因是因为char
类型没有定义+
运算符,所以C#恢复为最近的兼容类型,恰好是int
。 (Source)
因此,要实现此行为,您将需要执行与F#中已经尝试执行的操作类似的操作:
char a = 'a';
char b = 'b';
// This is the wrong way to concatenate chars, because the
// chars will be treated as ints and the result will be 195.
Console.WriteLine(a + b);
// These are the correct ways to concatenate characters into
// a single string. The result of all of these will be "ab".
// The third way is the recommended way as it is concise and
// involves creating the fewest temporary objects.
Console.WriteLine(a.ToString() + b.ToString());
Console.WriteLine(Char.ToString(a) + Char.ToString(b));
Console.WriteLine(new String(new[] { a, b }));
(请参阅https://dotnetfiddle.net/aEh1FI)
F#与连接两个或更多char
不会导致String
相同。与C#不同,它代替的结果是另一个char
,但是过程是相同的-char
的值被视为int
并加在一起,结果是char
和的表示。
实际上,在F#中将char
连接成String
的方式就是您已经拥有的,并且是C#等价物的直接翻译:
let a = 'a'
let b = 'b'
// This is still the wrong way (prints 'Ã')
printfn "%O" (a + b)
// These are still the right ways (prints "ab")
printfn "%O" (a.ToString() + b.ToString())
printfn "%O" (Char.ToString(a) + Char.ToString(b))
printfn "%O" (String [| a;b |]) // This is still the best way
(请参阅https://dotnetfiddle.net/ALwI3V)
“从字符数组中获取字符串”方法是最佳方法的原因有两个。首先,它是最简洁的,因为您可以看到该方法提供了两种语言中最短的代码行(并且差异仅随着您将越来越多的char
加在一起而增加)。其次,在最终String
之前仅创建一个临时对象(数组),而其他两种方法涉及制作两个单独的临时String
对象以馈入最终结果。
(此外,由于 String
构造函数被隐藏在外部源中,因此我不确定它是否以此方式工作,但我想传递给该构造函数的数组将用作{{ 1}}的数据支持,因此最终不会浪费。)String
是不可变的,但是将传递的数组直接用作创建的String
支持数据可能会导致对数组的引用可能保存在程序的其他位置,并危及String
的不变性,因此这种猜测在实践中不会奏效。 (来源:@CaringDev)
在F#中可以做得更惯用的另一种选择是使用String
函数来组合两个字符(贷方:@rmunn):
sprintf
(请参阅https://dotnetfiddle.net/Pp9Tee)
但是,有关此方法的警告提示是,几乎可以肯定,它会比上面列出的其他三种方法中的任何一种都要慢得多。这是因为let a = 'a'
let b = 'b'
let s = sprintf "%c%c" a b
printfn "%O" s
// Prints "ab"
会直接在输出上执行更高级的格式化逻辑,而不是直接处理数组或String
数据。 (我目前无法自己进行基准测试,但是将其插入下面的@TomasPetricek的benckmarking代码中,如果您获得10倍或更多的性能命中率,我也不会感到惊讶。)
这可能并不重要,因为对于一次转换而言,它仍然比任何最终用户可能注意到的速度都要快得多,但是请注意,如果将其用于任何对性能要求严格的代码中,则要小心。
答案 1 :(得分:4)
@ Abion47的答案已经列出了我能想到的所有可能的明智方法。如果您对性能感兴趣,则可以使用F#Interactive #time
功能进行快速实验:
#time
open System
open System.Text
let a = 'a'
let b = 'b'
将这三种方法进行比较,事实证明,使用String [| a; b |]
的方法的速度大约是使用ToString
的方法的两倍。在实践中,这可能不是一个大问题,除非你正在做几百万这样的操作(如我的实验一样),但它是一个有趣的事实就知道:
// 432ms, 468ms, 472ms
for i in 0 .. 10000000 do
let s = a.ToString() + b.ToString()
ignore s
// 396ms 440ms, 458ms
for i in 0 .. 10000000 do
let s = Char.ToString(a) + Char.ToString(b)
ignore s
// 201ms, 171ms, 170ms
for i in 0 .. 10000000 do
let s = String [| a;b |]
ignore s