為什麼很多語言中,要用三個引號或其他符號來表示多行字元串字面量?

這有什麼必要嗎?perl 和 rust 只用一個引號沒什麼問題吧…

但是老的語言如 python(三個引號)等,新的語言如 go(反引號)、swift(三個引號)、ES6(反引號)、TOML(三個引號)等都由刻意區分單行字元串和多行字元串的寫法,這是出於什麼原因呢?ES6 即使將一個引號擴展成可以用於多行字元串也不會有兼容性問題吧…?


這個叫「heredoc」,起源於Unix shell,之後在許多Unix Style的編程語言中都有實現,比如Perl、PHP、Ruby,當然也包括Python,它是多行字元串字面量的一種形式,會保留文本原來的模樣,包括引號、換行符及各種whitespace(空格、Tab)。

PHP中的heredoc可以引用變數:

比如:

&
&
&Here Doc&
&

&
&

{$name}& &
&
EOT;

輸出為:

而PHP中還有一個nowdoc,則不會解析引用變數,特別適合輸出程序樣例,比如:

輸出:


單個引號表示多行字元串字面量當然沒問題,支不支持問題其實都不大,不支持多行的原因可能只是為了照顧習慣而已,你看clojure雙引號字元串內就能有換行符。選擇三引號的原因一般是三引號一般不會出現在常規的字元串中,用它界定很少會出現非用其他特殊形式表示不可的情況,用來表示原生字元串是個不錯的選擇。


Python

如果使用換行,單引號

In [9]: s = hello
...: world
In [10]: print(s)
helloworld

三個引號

In [11]: s = hello
...: world
In [12]: print(s)
hello
world

可以看出 Python 使用單引號想換行需要在末尾加上 ,否則會抱錯,然後字元串被解釋為 helloworld,輸出中兩個詞中間沒有換行(評論中提出,可以用使用字面量連接,直接字面量連接或者 + 操作都可以,這裡用哪種方法都行。)。而使用 ,字元可以隨意換行直到遇到另一個 ,字元串被解釋為 hello
world,換行符被保留下了。

Golang

雙引號用來創建可解析的字元串字面量,支持轉義序列,但不能引用多行。可以這樣寫多行

s := "hello" +
"world"

輸出同樣是 helloworld

反引號用來創建原生的字元串字面量,可由多行組成,不支持任何轉義序列。

s := `hello
world`

輸出

hello
world

換行符同樣被保留。

JavaScript

雙引號

s = "hello" +
"world"
"helloworld"

反引號

s = `hello
world`
"hello
world"

同樣換行符被保留,事實上反引號用來標記模板字元串,還有個作用是再解釋內部的一些符號。

上面可以看出,不同語言使用多種引號,是因為它們的功能側重點不同。在 Python 和 Golang 裡面,多行引用一般都代表原生字元串字面量,多用於 HTML / 正則表達式 / 多行消息(有換號),python 也有直接拿它當注釋的。而雙引號/單引號代表可轉義字元串,用於一般場景。Javascript 的側重點又有所不同。

這些語言可不可以用只用一種引號來表達所有情況?

可以

但這樣會讓語法變得更加複雜,難以編寫,可讀性也很差。

有些也存在兼容性問題。比如問題中提到的 ES6 反引號,如果直接使用單引號或者雙引號,那麼原來的字元串都變成了模板字元串,裡面的符號將可能被解釋為其他含義。

比如

user = "hello"
"hello"
"${user}"
"hello"

原本 "${user}" 的輸出就是 "${user}",現在變成了 "hello"。


推薦閱讀:

關於 Type Inference 的各種應用和學習資料?
三宮六院七十二妃(程序YUAN版)
做web開發需要在工作中注意哪些安全方面的問題?
比較Lua和Go語言

TAG:編程語言 | 編譯原理 | 標記語言 |