为什么 F# 三引号字符串不能以双引号结尾?

9
我是一名C#开发者,正在尝试学习F#。
据我所知,F# 2.0有两种字符串语法:普通字符串和逐字字符串(C#中的用法)。随着F# 3.0版本的推出,增加了一个名为“三引号字符串”的功能。
据我观察,使用这种字符串格式,位于"""之间的所有内容都是逐字字符串文字。而且不需要转义双引号等转义序列字符
例如,下面所有字符串都是有效的:
let a = """ This is a valid "string" """
let b = """ This is a valid \string """
let c = """ This is a valid 'string """

但是它有一个规则;

三引号字符串中的引号不能以双引号(“)结尾,但可以以其开始。

所以这是一个合法的字符串;

let s = """"This is a valid string"""

但这不是;
let s = """This is a valid string""""

为什么呢?我查看了{{link1:MSDN页面上的Strings (F#)}},{{link2:F# 3.0语言规范$3.5字符串和字符部分}}和{{link3:更多关于F# 3.0语言特性的信息}},但我没有找到任何关于为什么可以在字符串开头使用它而不能在结尾使用它的信息。
你能为我解释一下吗?

可能会混淆词法分析器/记号生成器。我猜你只需要在第一个"后加一个空格。 - leppie
@Downvoter,您能否至少评论一下,这样我就可以看到_might_做错了什么? - Soner Gönül
2个回答

8
答案很简单:三个引号结束的字符串在编译器看到三个引号时就结束了。所以"""a""""是一个由字符a组成的字符串,后面跟着一个额外的",这个"开始了一个新的字符串。
如果你想写混淆代码,你可以这样做:
f"""a""""b"

调用函数 f ,并传入两个字符串参数 "a""b"

嗯,我个人认为你的答案是有道理的。点赞。但是为什么编译器不考虑最后三个引号而是前三个呢?因为在字符串开头,编译器会考虑前三个引号。这部分之后的引号,编译器会将它们视为字符串的一部分。例如;""""""a"""可能是一个空字符串,因为除了前面3个引号之外还有3个引号。当编译器看到这3个引号时,它可能会说“好的,让我们结束这个字符串”。至少应该给出编译时错误。但这是一个有效的字符串,这让我感到困惑。 - Soner Gönül
3
@SonerGönül:实际上 """"""a""" 会导致编译时错误。正如您所预期的,三重引号字符串可以以一个或两个引号开始,但不能以三个引号开始。 - Tarmil

0

使用字符串插值的Hacky解决方法(因此需要F# 5+):

let doubleQuote = '"'
let x = $"""User said "something{doubleQuote}"""
printf "%s" x

忽略语法高亮,SO无法处理 `""""`

忽略上面的内容。Bent下面的建议使用 + 更清晰,运行时特性更好。


问题并不是如何绕过限制,而是为什么首先会有这样的限制。如果你想在末尾添加引用,最简单的方法可能就是使用加号运算符将其添加到原始字符串中。在最好的情况下,编译器甚至可以在编译时完成它,避免不必要的运行时指令。 - Bent Tranberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接