插入字串

插入字串是可讓您將 F# 運算式內嵌到其中的 字串 。 在各種案例中,字串的值可能會根據值或表達式的結果而變更,這很實用。

語法

$"string-text {expr}"
$"string-text %format-specifier{expr}"
$@"string-text {expr}"
@$"string-text {expr}"
$"""string-text {"embedded string literal"}"""
$$"""string-text %%format-specifier{{expr}}"""

備註

插入字串可讓您在字串常值內的「漏洞」中撰寫程序代碼。 以下是基本範例:

let name = "Phillip"
let age = 30
printfn $"Name: {name}, Age: {age}"

printfn $"I think {3.0 + 0.14} is close to {System.Math.PI}!"

每個 {} 大括弧組之間的內容可以是任何 F# 運算式。

對於 F# 11 中的字串值插值,未格式化的表達式使用 F# 的 string 轉換。 如果運算式的評估結果為 null,則會使用空字串。 早期編譯器能優化部分僅字串插值,但其他方式仍使用 printf 格式;關於格式差異,請參見 Native AOT 與字串值插值 。

對於具有格式指定元 (例如 %s{expr} 或 %d{expr}) 的類型內插字串,轉換會遵循針對該特定格式指定元定義的規則。 若要逸出大括弧組,請撰寫其中兩個 {} ,如下所示:

let str = $"A pair of braces: {{}}"
// "A pair of braces: {}"

具類型的插補字串

插補字串也可以有 F# 格式規範來強制執行類型安全性。

let name = "Phillip"
let age = 30

printfn $"Name: %s{name}, Age: %d{age}"

// Error: type mismatch
printfn $"Name: %s{age}, Age: %d{name}"

在上一個範例中,程式代碼錯誤地傳遞應為 age 的值 name ,反之亦然。 因為插補字串使用格式規範,因此這是編譯錯誤,而不是細微的運行時間錯誤。

逐字插入字串

F# 以兩種方式支援逐字插補字串:

使用 $@ 或 @$ 前置詞

您可以以任何順序將插補字首 $ 與逐字字串字首 @ 結合。 逐字字串會忽略轉義序列 ( "" 表示引號除外) ,而且可以跨越多行。 這在處理包含反斜線和引號的檔案路徑或字串時特別有用。

let name = "Alice"
let path = @"C:\Users\Alice\Documents"

// Using $@ prefix
printfn $@"User {name} has files in: {path}"

// Using @$ prefix (also valid)
printfn @$"User {name} has files in: {path}"

// Embedding quotes - use "" to represent a single "
let message = $@"He said ""{name}"" is here"

使用三重引號

F# 也支援使用三引號的逐字插補字串,讓您可以內嵌字串常值,而不會逸出。

let age = 30

printfn $"""Name: {"Phillip"}, Age: %d{age}"""

格式規範

格式規範可以是 printf 樣式或 。NET 樣式。 Printf 樣式規範是以 純文本格式所涵蓋的規範,放在大括弧之前。 例如:

let pi = $"%0.3f{System.Math.PI}"  // "3.142"
let code = $"0x%08x{43962}"  // "0x0000abba"

格式規範 %A 特別適用於產生結構化 F# 資料的診斷輸出。

let data = [0..4]
let output = $"The data is %A{data}"  // "The data is [0; 1; 2; 3; 4]"

.NET 樣式規範是那些可在 String.Format大括弧內 : 使用 的規範。 例如:

let pi = $"{System.Math.PI:N4}"  // "3.1416"
let now = $"{System.DateTime.UtcNow:``yyyyMMdd``}" // for example, "20220210"

如果 為 。NET 樣式規範包含不尋常的字元,然後可以使用雙反引號逸出:

let nowDashes = $"{System.DateTime.UtcNow:``yyyy-MM-dd``}" // for example, "2022-02-10"

在插入字串中對齊表達式

您可以在內插補字串內靠左對齊或靠右對齊表達式, | 以及指定多少個空格。 下列插補字串會將左右表達式分別靠左和右對齊七個空格。

printfn $"""|{"Left",-7}|{"Right",7}|"""
// |Left   |  Right|

插入字串和 FormattableString 格式設定

您也可以套用符合 下列規則的格式 FormattableString:

let speedOfLight = 299792.458
printfn $"The speed of light is {speedOfLight:N3} km/s."
// "The speed of light is 299,792.458 km/s."

此外,插補字串也可以透過型別批注來檢查為 FormattableString :

let frmtStr = $"The speed of light is {speedOfLight:N3} km/s." : FormattableString
// Type: FormattableString
// The speed of light is 299,792.458 km/s.

請注意,類型批註必須位於插入字串表示式本身上。 F# 不會隱含地將插入字串轉換成 FormattableString。

字串插補的擴充語法

從 F# 8 開始,當您使用包含多個 {、 } 或 % 字元的文字時,您可以使用擴充字串插補語法來移除逸出的需求。

三引號字串常值可以從多個 $ 字元開始,這會變更開啟和關閉插補所需的大括號數目。 在這些字串常值中, { 和 } 字元不需要逸出:

let str = $$"""A string containing some {curly braces} and an {{"F#" + " " + "expression"}}."""
// "A string containing some {curly braces} and an F# expression."
let another = $$$"""A string with pairs of {{ and }} characters and {{{ "an F# expression" }}}."""
// "A string with pairs of {{ and }} characters and an F# expression."""

格式規範所需的字元數 % 會以相同方式受到影響:

let percent = $$"""50% of 20 is %%.1f{{20m * 0.5m}}"""
// "50% of 20 is 10.0"

原生AOT與字串值插值

若要在沒有反射格式引擎的情況下格式化文字,請使用字串值插值,並使用純 PAGE 或 .NET 格式的空洞:

let name = "Ada"
let score = 97.5
let message: string = $"{name}: {score:F1}"
printn message
// Ada: 97.5

F# 11 使用直接轉換及 System.String.Concat 更多字串值插值。 .NET格式的洞使用不變String.Format式並框住其參數。 這些編譯器變更支援 原生AOT ,無需現代核心編譯;其他應用程式碼仍可能需要反射。

需要 printf 格式化的 printf 風格孔洞,如 %04d{number} 或 %A{record},仍可使用基於反射的路徑。 裸、%s%c、%d、 %i%M 和 孔會保留其型別檢查,避免 printf 格式化。 其他規範子,包括 %u,不包含在該優化範圍內。 用作 PrintfFormat 值的插值也不同於結果型別為 string的插值。

文化與格式相容性

普通洞使用 F# string 的轉換;.NET格式的洞使用不變格式化。 要產生在地化輸出,請明確選擇培養物:

open System.Globalization

let value = 12.5m
let machineText: string = $"{value:F2}"
let displayText =
    value.ToString("F2", CultureInfo.GetCultureInfo("fr-FR"))

assert (machineText = "12.50")
assert (displayText = "12,50")

升級時要檢查本地輸出。 FormattableString 保留了後來基於提供者格式的論點,而非遵循此串接路徑。

警告 FS3884 會識別插值漏洞中的未套用函數或代理。 如果你想要得到的結果,請應用該函數:

let weight () = 12.5m
let text: string = $"Weight: {weight ()} kg"

將值寫入標準輸出

若要寫入沒有 printf 格式的值,FSharp.Core 11 會 print 加上 和 printn。 他們使用 string 換算; printn 並加入一個換行:

print "Parcels: "
printn 3

結構 %A 性輸出則使用 純文字格式。

記錄與聯合輸出(無反射)

有了 --reflectionfree,F# 11 可以產生有 ToString 意義的記錄與聯集實作,而非僅顯示型別名稱:

type Reading = { Sensor: string; Value: int }
type Outcome = Recorded of Reading | Unavailable

let reading = { Sensor = "north"; Value = 12 }
printn reading
printn (Recorded reading)

範例專案啟用了旗幟。 輸出與 %A;欄位類型也需要適當的 ToString 實作。

另請參閱