值
值是藉由評估運算式所產生的資料。 本節描述 M 語言中的值種類。 每個種類的值都與常值語法、一組屬於該種類的值、一組在該值上定義的運算子,以及歸屬於新建立值的內建類型建立關聯。
種類 | 常值 |
---|---|
Null | null |
邏輯 | true false |
Number | 0 1 -1 1.5 2.3e-5 |
Time | #time(09,15,00) |
日期 | #date(2013,02,26) |
DateTime | #datetime(2013,02,26, 09,15,00) |
DateTimeZone | #datetimezone(2013,02,26, 09,15,00, 09,00) |
期間 | #duration(0,1,30,0) |
Text | "hello" |
二進位 | #binary("AQID") |
清單 | {1, 2, 3} |
錄製 | [ A = 1, B = 2 ] |
Table | #table({"X","Y"},{{0,1},{1,0}}) |
Function | (x) => x + 1 |
類型 | type { number } type table [ A = any, B = text ] |
下列章節將詳述每個值種類。 類型和類型歸屬,正式定義於類型中。 函式值定義於函式中。 下列章節列出針對每個值種類所定義的運算子,並提供範例。 運算子語義的完整定義,位於運算子中。
「Null 值」用來表示缺少的值,或值為不確定或未知狀態。 Null 值使用 null
常值撰寫。 下列運算子針對 Null 值定義:
運算子 | 結果 |
---|---|
x > y |
大於 |
x >= y |
大於或等於 |
x < y |
小於 |
x <= y |
小於或等於 |
x = y |
等於 |
x <> y |
不等於 |
x ?? y |
Coalesce |
null
值的原生類型是內建類型 null
。
「邏輯值」用於布林運算,具有 True 或 False 值。 邏輯值使用 true
和 false
常值撰寫。 下列運算子針對邏輯值定義:
運算子 | 結果 |
---|---|
x > y |
大於 |
x >= y |
大於或等於 |
x < y |
小於 |
x <= y |
小於或等於 |
x = y |
等於 |
x <> y |
不等於 |
x or y |
條件邏輯 OR |
x ?? y |
Coalesce |
x and y |
條件邏輯 AND |
not x |
邏輯 NOT |
邏輯值 (true
和 false
) 的原生類型是 logical
內建類型。
「數字值」用於數值和算數運算。 下列是數字常值的範例:
3.14 // Fractional number
-1.5 // Fractional number
1.0e3 // Fractional number with exponent
123 // Whole number
1e3 // Whole number with exponent
0xff // Whole number in hex (255)
數字至少以 Double 精確度來表示 (但可能會保留更多有效位數)。 Double 表示法與 [IEEE 754-2008] 中所定義二進位浮點算術的 IEEE 64 位元雙精確度標準一致。 (Double 表示法具有大約從 5.0 x 10324 到 1.7 x 10308 的動態範圍,精確度為 15-16 位數。)
下列特殊值也會視為「數字」值:
正零和負零。 在大部分情況下,正零和負零的行為與簡單值零相同,但某些運算會區分這兩個值。
正無限 (
#infinity
) 和負無限 (-#infinity
)。 無限是藉由將非零數字除以零之類的運算來產生。 例如,1.0 / 0.0
會產生正無限,-1.0 / 0.0
會產生負無限。Not-a-Number 值 (
#nan
) 通常縮寫為 NaN。 NaN 是由不正確的浮點運算所產生,例如零除以零。
二進位數學運算會使用「精確度」來執行。 精確度會決定要將運算元四捨五入的定義域,以及要在其中執行作業的定義域。 如果沒有明確指定精確度,則會使用「雙精確度」來執行這類作業。
如果數學運算的結果太小,無法用於目標格式,則運算的結果會變成正零或負零。
如果數學運算的結果太大,無法用於目標格式,則運算的結果會變成正無限或負無限。
如果數學運算無效,則運算的結果會變成 NaN。
如果浮點運算的一或兩個運算元都是 NaN,則運算的結果會變成 NaN。
下列運算子針對數值定義:
運算子 | 結果 |
---|---|
x > y |
大於 |
x >= y |
大於或等於 |
x < y |
小於 |
x <= y |
小於或等於 |
x = y |
等於 |
x <> y |
不等於 |
x + y |
Sum |
x - y |
差數 |
x * y |
Products |
x / y |
商數 |
x ?? y |
Coalesce |
+x |
一元加號 |
-x |
否定 |
數值的原生類型是內建類型 number
。
「時間值」會儲存一天中時間的不透明表示。 時間會編碼為「從午夜起的刻度」數,以 24 小時制時間來計算 100 奈秒刻度數。 「從午夜起的刻度」數會對應至 23:59:59.9999999 小時。
雖然 times 沒有常值語法,但會提供數個標準程式庫函式來加以建構。 Times 也可以使用 #time
內建函式來建構:
#time(hour, minute, second)
下列項目必須保留,否則會以原因代碼 Expression.Error
引發錯誤:
0 ≤ 小時 ≤ 24
0 ≤ 分鐘 ≤ 59
0 ≤ 秒 ≤ 59
此外,如果 hour = 24,則 minute 和 second 必須為零。
下列運算子針對時間值定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x ?? y |
Coalesce |
下列運算子允許其一或兩個運算元都是日期:
運算子 | 左運算元 | 右運算元 | 意義 |
---|---|---|---|
x + y |
time |
duration |
依據期間位移後的日期 |
x + y |
duration |
time |
依據期間位移後的日期 |
x - y |
time |
duration |
依據負期間位移後的日期 |
x - y |
time |
time |
日期之間的期間 |
x & y |
date |
time |
合併後的日期時間 |
類型值的原生類型是內建類型 time
。
「時間值」會儲存特定日期的不透明表示。 日期是以「紀元起算的天數」來編碼,從西曆的 0001 年 1 月 1 日開始。 自紀元起算的天數上限為 3652058,對應於 9999 年 12 月 31 日。
雖然 dates 沒有常值語法,但會提供數個標準程式庫函式來加以建構。 Dates 也可以使用 #date
內建函式來建構:
#date(year, month, day)
下列項目必須保留,否則會以原因代碼 Expression.Error
引發錯誤:
1 ≤ 年 ≤ 9999
1 ≤ 月 ≤ 12
1 ≤ 日 ≤ 31
此外,日期必須對所選的月份和年份有效。
下列運算子針對日期值定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x ?? y |
Coalesce |
下列運算子允許其一或兩個運算元都是日期:
運算子 | 左運算元 | 右運算元 | 意義 |
---|---|---|---|
x + y |
date |
duration |
依據期間位移後的日期 |
x + y |
duration |
date |
依據期間位移後的日期 |
x - y |
date |
duration |
依據負期間位移後的日期 |
x - y |
date |
date |
日期之間的期間 |
x & y |
date |
time |
合併後的日期時間 |
日期值的原生類型是內建類型 date
。
「日期時間值」同時包含日期和時間。
雖然 datetimes 沒有常值語法,但會提供數個標準程式庫函式來加以建構。 Datetimes 也可以使用內建函式 #datetime
來建構:
#datetime(year, month, day, hour, minute, second)
下列項目必須保留,否則會以原因代碼 Expression.Error 引發錯誤:1 ≤ year ≤ 9999
1 ≤ 月 ≤ 12
1 ≤ 日 ≤ 31
0 ≤ 小時 ≤ 23
0 ≤ 分鐘 ≤ 59
0 ≤ 秒 ≤ 59
此外,日期必須對所選的月份和年份有效。
下列運算子針對日期時間值定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x ?? y |
Coalesce |
下列運算子允許其一或兩個運算元都是日期時間:
運算子 | 左運算元 | 右運算元 | 意義 |
---|---|---|---|
x + y |
datetime |
duration |
依據期間位移後的日期時間 |
x + y |
duration |
datetime |
依據期間位移後的日期時間 |
x - y |
datetime |
duration |
依據負期間位移後的日期時間 |
x - y |
datetime |
datetime |
日期時間之間的期間 |
日期時間值的原生類型是內建類型 datetime
。
datetimezone 值包含日期時間和時區。 「時區」會以「與 UTC 的分鐘數時差」來編碼,其會計算「日期時間」時間部分與國際標準時間 (UTC) 的分鐘數時差。 「與 UTC 的分鐘數時差」最小數目為 -840,代表 -14:00 的 UTC 時差,或比 UTC 早十四小時。 「與 UTC 的分鐘數時差」最大數目為 840,對應於 14:00 的 UTC 時差。
雖然 datetimezones 沒有常值語法,但會提供數個標準程式庫函式來加以建構。 Datetimezones 也可以使用內建函式 #datetimezone
來建構:
#datetimezone(
year, month, day,
hour, minute, second,
offset-hours, offset-minutes)
下列項目必須保留,否則會以原因代碼 Expression.Error
引發錯誤:
1 ≤ 年 ≤ 9999
1 ≤ 月 ≤ 12
1 ≤ 日 ≤ 31
0 ≤ 小時 ≤ 23
0 ≤ 分鐘 ≤ 59
0 ≤ 秒 ≤ 59
-14 ≤ offset-hours ≤ 14
-59 ≤ offset-minutes ≤ 59
此外,日期必須適用於所選的月份和年份,如果 offset-hours = 14,則 offset-minutes <= 0,而如果 offset-hours = -14,則 offset-minutes >= 0。
下列運算子針對 datetimezone 值定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x ?? y |
Coalesce |
下列運算子允許其一或兩個運算元都是 datetimezone:
運算子 | 左運算元 | 右運算元 | 意義 |
---|---|---|---|
x + y |
datetimezone |
duration |
依據期間位移後的日期時區 |
x + y |
duration |
datetimezone |
依據期間位移後的日期時區 |
x - y |
datetimezone |
duration |
依據負間位移後的日期時區 |
x - y |
datetimezone |
datetimezone |
日期時區之間的期間 |
datetimezone 值的原生類型是內建類型 datetimezone
。
「持續時間值」會儲存時間軸上兩個點之間距離的不透明表示,以 100 奈秒刻度數來測量。 「持續時間」的範圍可以是正數或負數,其正值表示時間往前的進度,負值則代表時間往後的進度。 可以在「持續時間」內儲存的最小值為 -9,223,372,036,854,775,808 刻度,或 10,675,199 天 2 小時 48分鐘 05.4775808 秒往前的時間。 可以在「持續時間」內儲存的最大值為 9,223,372,036,854,775,807 刻度,或 10,675,199 天 2 小時 48 分鐘 05.4775807 秒往後的時間。
雖然 durations 沒有常值語法,但會提供數個標準程式庫函式來加以建構。 Durations 也可以使用內建函式 #duration
來建構:
#duration(0, 0, 0, 5.5) // 5.5 seconds
#duration(0, 0, 0, -5.5) // -5.5 seconds
#duration(0, 0, 5, 30) // 5.5 minutes
#duration(0, 0, 5, -30) // 4.5 minutes
#duration(0, 24, 0, 0) // 1 day
#duration(1, 0, 0, 0) // 1 day
下列運算子在持續時間值上定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x ?? y |
Coalesce |
此外,下列運算子允許其一或兩個運算元都是持續時間值:
運算子 | 左運算元 | 右運算元 | 意義 |
---|---|---|---|
x + y |
datetime |
duration |
依據期間位移後的日期時間 |
x + y |
duration |
datetime |
依據期間位移後的日期時間 |
x + y |
duration |
duration |
期間的總和 |
x - y |
datetime |
duration |
依據負期間位移後的日期時間 |
x - y |
datetime |
datetime |
日期時間之間的期間 |
x - y |
duration |
duration |
期間的差異 |
x * y |
duration |
number |
期間乘以 N 次 |
x * y |
number |
duration |
期間乘以 N 次 |
x / y |
duration |
number |
期間的分數 |
持續時間值的原生類型是內建類型 duration
。
「文字」值表示 Unicode 字元序列。 文字值的常值格式符合下列文法:
_text-literal:
"
text-literal-charactersopt "
text-literal-characters:
text-literal-character text-literal-charactersopt
text-literal-character:
single-text-character
character-escape-sequence
double-quote-escape-sequence
single-text-character:
"
以外的任何字元 (U+0022
) 或 #
(U+0023
),後面接著 (
(U+0028
)
double-quote-escape-sequence:
下列為「文字」值的範例:
"ABC" // the text value ABC
下列運算子在「文字」值上定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x & y |
串連 |
x ?? y |
Coalesce |
文字值的原生類型是內建類型 text
。
「二進位值」代表位元組序列。
雖然二進位值沒有常值語法,但會提供數個標準程式庫函式來加以建構。 二進位值也可以使用內建函式 #binary
來建構。
下列範例會從位元組清單中建構二進位值:
#binary( {0x00, 0x01, 0x02, 0x03} )
下列運算子在「二進位」值上定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x >= y |
大於或等於 |
x > y |
大於 |
x < y |
小於 |
x <= y |
小於或等於 |
x ?? y |
Coalesce |
二進位值的原生類型是內建類型 binary。
「清單值」是會在列舉時產生一系列值的值。 清單所產生值可以包含任何類型的值,包括清單。 您可使用初始化語法來建構清單,如下所示:
list-expression:
{ item-listopt }
item-list:
項目
item ,
item-list
item:
expression
運算式 ..
運算式
下列是 list-expression 的範例,其會以三個文字值來定義清單:"A"
、"B"
和 "C"
。
{"A", "B", "C"}
"A"
值是清單中的第一個項目,而 "C"
值是清單中的最後一個項目。
- 清單的項目不會在存取之前進行評估。
- 雖然使用清單語法所建立清單值會以其顯示在 item-list 中的順序來產生項目,但在一般情況下,從程式庫函式傳回的清單,可能會在每次列舉時產生不同集合或不同數目的值。
若要在清單中包含整數序列,可使用 a..b
格式:
{ 1, 5..9, 11 } // { 1, 5, 6, 7, 8, 9, 11 }
清單中的項目數 (也稱為「清單計數」) 可使用 List.Count
函式來決定。
List.Count({true, false}) // 2
List.Count({}) // 0
清單可有效地擁有無限數量的項目;這類清單的 List.Count
尚未定義,且可能會引發錯誤或無法終止。
如果清單中未包含任何項目,則其稱為「空白清單」。 空白清單會寫成:
{} // empty list
下列運算子針對清單定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x & y |
Concatenate |
x ?? y |
Coalesce |
例如:
{1, 2} & {3, 4, 5} // {1, 2, 3, 4, 5}
{1, 2} = {1, 2} // true
{2, 1} <> {1, 2} // true
清單值的原生類型是 list
內建類型,其會指定 any
的項目類型。
「記錄值」是依序排列的欄位序列。 「欄位」包含「欄位名稱」(可唯一識別記錄內欄位的文字值) 及「欄位值」。 欄位值可以是任何種類的值,包括記錄。 您可使用初始化語法來建構記錄,如下所示:
record-expression:
[
field-listopt ]
field-list:
field
field ,
field-list
field:
field-name =
expression
field-name:
generalized-identifier
quoted-identifier
下列範例使用名為 x
且值為 1
的欄位,以及名為 y
且值為 2
的欄位來建構記錄。
[ x = 1, y = 2 ]
下列範例使用以巢狀記錄值命名的 a
欄位來建構記錄。 此巢狀記錄具有名為 b
的欄位,其值為 2
。
[ a = [ b = 2 ] ]
評估記錄運算式時會發生下列情況:
指派給每個欄位名稱的運算式,會用來判斷相關聯欄位的值。
如果指派給欄位名稱的運算式在評估時產生值,則該值會成為所產生記錄的欄位值。
如果指派給欄位名稱的運算式在評估時引發錯誤,則引發錯誤的事實,會連同欄位及引發的錯誤值一起記錄。 對該欄位的後續存取,將會導致重新引發錯誤,並包含記錄的錯誤值。
運算式是在父環境之類的環境中評估,僅合併與記錄每個欄位其值對應的變數,除了用於初始化的變數以外。
在存取對應的欄位之前,不會評估記錄中的值。
記錄中的值最多只會評估一次。
運算式結果是具有空白中繼資料記錄的記錄值。
記錄內欄位的順序,是以其出現在 record-initializer-expression 中的順序來定義。
所指定每個欄位名稱在記錄內都必須是唯一的,否則會發生錯誤。 名稱會使用序數比較來進行比較。
[ x = 1, x = 2 ] // error: field names must be unique
[ X = 1, x = 2 ] // OK
不具有任何欄位的記錄稱為「空白記錄」,其撰寫方式如下:
[] // empty record
雖然在存取欄位或比較兩筆記錄時,記錄欄位的順序並不重要,但在其他內容中 (例如在列舉記錄的欄位時) 則很重要。
取得欄位時,兩筆相同記錄會產生不同的結果:
Record.FieldNames([ x = 1, y = 2 ]) // [ "x", "y" ]
Record.FieldNames([ y = 1, x = 2 ]) // [ "y", "x" ]
您可使用 Record.FieldCount
函式來判斷記錄中的欄位數目。 例如:
Record.FieldCount([ x = 1, y = 2 }) // 2
Record.FieldCount([]) // 0
除了使用記錄初始化語法 [ ]
,您也可以從值清單及欄位名稱或記錄類型清單來建構記錄。 例如:
Record.FromList({1, 2}, {"a", "b"})
上述相當於:
[ a = 1, b = 2 ]
下列運算子針對記錄定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x & y |
合併 |
x ?? y |
Coalesce |
下列範例說明上述運算子。 請注意,如果欄位名稱有重疊,則記錄合併會使用右運算元中欄位來覆寫左運算元的欄位。
[ a = 1, b = 2 ] & [ c = 3 ] // [ a = 1, b = 2, c = 3 ]
[ a = 1, b = 2 ] & [ a = 3 ] // [ a = 3, b = 2 ]
[ a = 1, b = 2 ] = [ b = 2, a = 1 ] // true
[ a = 1, b = 2, c = 3 ] <> [ a = 1, b = 2 ] // true
記錄值的原生類型是 record
內建類型,其會指定欄位的開放空白清單。
「資料表值」是依序排列的資料列序列。 「資料列」是依序排列的資料行值序列。 資料表類型會決定資料表中所有資料列的長度、資料表資料行的名稱、資料表資料行的類型,以及資料表索引鍵的結構 (如果有的話)。
雖然資料表沒有常值語法,但會提供數個標準程式庫函式來加以建構。 資料表也可以使用 #table
內建函式來建構。
下列範例會從資料行名稱和資料列清單建構資料表。 產生的資料表將包含兩個 type any
資料行和三個資料行。
#table({"x", "x^2"}, {{1,1}, {2,4}, {3,9}})
#table
也可以用來指定完整資料表類型:
#table(
type table [Digit = number, Name = text],
{{1,"one"}, {2,"two"}, {3,"three"}}
)
在這裡,新的資料表值有一個資料表類型,其會指定資料行名稱和資料行類型。
下列運算子針對資料表值定義:
運算子 | 結果 |
---|---|
x = y |
等於 |
x <> y |
不等於 |
x & y |
串連 |
x ?? y |
Coalesce |
資料表串連會將名稱類似的資料行對齊,並會為僅出現在一個運算元資料表的資料行填入 null
。 下列範例說明資料表串連:
#table({"A","B"}, {{1,2}})
& #table({"B","C"}, {{3,4}})
A | B | C |
---|---|---|
1 |
2 |
null |
null |
3 |
4 |
資料表值的原生類型是自訂資料表類型 (衍生自內建類型 table
),其會列出資料行名稱、指定所有資料行類型為任何類型,且沒有索引鍵。 (如需資料表類型的詳細資訊,請移至資料表類型。)
「函式值」是將一組引數對應到單一值的值。 「函式」值的詳細資料於函式中描述。
「類型值」是分類其他值的值。 「類型」值的詳細資料於類型中描述。