類型
「類型值」是「分類」其他值的值。 由類型分類的值稱為「符合」該類型。 M 類型系統由下列類型種類組成:
基本類型,這些類型會分類基本值 (
binary、date、datetime、datetimezone、duration、list、logical、null、number、record、text、time、type),也包含一些抽象類型 (function、table、any、none)記錄類型,其根據欄位名稱和值類型來分類記錄值
清單類型,其使用單一項目基底類型來分類清單
函式類型,其根據函式的參數和傳回值來分類函式值
資料表類型,其根據資料行名稱、資料行類型和索引鍵來分類資料表值
可為 Null 的型別,其分類 Null 值和所有由基底類型分類的值
類型類型,其分類本身是類型的值
「基本類型」集合包含基本值的類型、一些「抽象類型」值、無法唯一分類任何值的類型:function、table、any及 none。 所以函式值都符合抽象類型 function,所有資料表值都符合抽象類型 table,所有值都符合抽象類型 any,且沒有任何值符合抽象類型 none。 none 類型的運算式必須引發錯誤或是終止失敗,因為無法產生任何符合 none 類型的值。 請注意,基本類型 function 和 table 為抽象類型,因為沒有任何函式或資料表分別直接符合這些類型。 基本類型 record 和 list 並非抽象類型,因為其分別代表沒有已定義欄位的開放式記錄和 any 類型清單。
所有並非基本類型封閉集合成員的類型都統稱為「自訂類型」。 自訂類型可以使用 type-expression 來撰寫:
type-expression:
primary-expression
typeprimary-type
類型:
parenthesized-expression
primary-type
primary-type:
基本類型
record-type
list-type
function-type
table-type
nullable-type
基本類型: 其中一個
any binary date datetime datetimezone duration function list logical
none null number record table text time type
primitive-type 名稱是只有在「類型」內容中才會識別的「內容關鍵字」。 在「類型」內容中使用括弧會將文法移回規則運算式內容,並要求使用 type 關鍵字來移回類型內容。 例如,若要在「類型」內容中呼叫函式,則可使用括弧:
type nullable ( Type.ForList({type number}) )
// type nullable {number}
括弧也可以用來存取名稱與 primitive-type 名稱衝突的變數:
let record = type [ A = any ] in type {(record)}
// type {[ A = any ]}
下列範例會定義分類數字清單的類型:
type { number }
同樣地,下列範例會定義自訂類型,其分類包含名為 X 和 Y 強制欄位,且其值是數字的記錄:
type [ X = number, Y = number ]
使用標準程式庫函式 Value.Type取得值的訂閱類型,如下列範例所示:
Value.Type( 2 ) // type number
Value.Type( {2} ) // type list
Value.Type( [ X = 1, Y = 2 ] ) // type record
is 運算子會用來判斷值的類型是否與指定類型相容,如下列範例中所示:
1 is number // true
1 is text // false
{2} is list // true
as 運算子會檢查值是否與指定類型相容,且在不相容時引發錯誤。 否則,其會傳回原始值。
Value.Type( 1 as number ) // type number
{2} as text // error, type mismatch
請注意,is 和 as 運算子只接受基本類型作為其右運算元。 M 沒有為自訂類型提供檢查值是否符合的方式。
只有在所有與 X 相符的值也都與 Y 相符時,類型 X 才與類型 Y「相容」。 所以類型都與 any 類型相容,且沒有任何類型 (但 none 本身除外) 與 none 類型相容。 下圖顯示相容性關聯。 (類型相容性是彈性且可轉移的。它會形成類型為頂端且類型 anynone 為底部值的延遲。) 抽象類別型的名稱是以 斜體設定。

其中已為類型值定義下列運算子:
| 運算子 | 結果 |
|---|---|
x = y |
等於 |
x <> y |
不等於 |
x ?? y |
Coalesce |
類型值的原生類型是內建類型 type。
基本類型
M 語言中類型構成根部為 any 類型的斷續階層,該類型同時也是分類所有值的類型。 任何 M 值都符合一個 any 的基本子類型。 衍生自 any 類型的基本類型封閉集合如下:
type null,它會分類 Null 值。type logical,其分類 true 和 false 值。type number,其分類數字值。type time,其分類時間值。type date,其分類日期值。type datetime,其分類日期時間值。type datetimezone,其分類 datetimezone 值。type duration,其分類持續時間值。type text,其分類文字值。type binary,其分類二進位值。type type,其分類類型值。type list,其分類清單值。type record,其分類記錄值。type table,其分類資料表值。type function,其分類函式值。type anynonnull,其分類所有除 Null 之外的值。none原生類型不會分類任何值。
任何類型
any 類型為抽象類型,會分類 M 中的所有值,且 M 中的所有類型皆和 any 相容。 any 類型的變數可以繫結至所有可能值。 因為 any 是抽象的,所以無法將它寫成值,也就是說,沒有值直接屬於 類型 any 。
清單類型
任何屬於清單的值都符合原生類型 list,此類型不會針對清單值內的項目施加任何限制。
list-type:
{item-type}
item-type:
type
評估 list-type 的結果是一個「清單類型值」,其基本類型為 list。
下列範例示範宣告同質清單類型的語法:
type { number } // list of numbers type
{ record } // list of records type
{{ text }} // list of lists of text values
如果值是清單且該清單值中每個項目都符合清單類型的項目類型,則該值便符合清單類型。
清單類型的項目類型會指出界限:符合清單的所有項目都符合項目類型。
記錄類型
任何屬於記錄的值都符合原生類型 record,此類型不會針對記錄值內的欄位名稱或值施加任何限制。 record-type-value 會用來限制有效名稱集合,以及允許與這些名稱建立關聯的值類型。
record-type:
[open-record-marker]
[field-specification-listopt]
[field-specification-list 、 open-record-marker]
field-specification-list:
field-specification
field-specification , field-specification-list
field-specification:
optionalopt field-name field-type-specificationopt
field-type-specification:
=field-type
field-type:
type
open-record-marker:
...
評估 record-type 的結果是一個類型值,其基本類型為 record。
下列範例示範宣告記錄類型的語法:
type [ X = number, Y = number]
type [ Name = text, Age = number ]
type [ Title = text, optional Description = text ]
type [ Name = text, ... ]
記錄類型根據預設是「封閉」的,這表示任何不存在 fieldspecification-list 中的其他欄位都不允許出現在符合值內。 在記錄類型中包含 openrecord-marker 會宣告類型為「開放」,其允許不存在於欄位規格清單中的欄位。 下列兩個運算式是對等的:
type record // primitive type classifying all records
type [ ... ] // custom type classifying all records
如果值是記錄且記錄類型中的每個欄位規格都獲得滿足,則值便符合記錄類型。 若下列任何一項為 true,欄位規格便會獲得滿足:
記錄中存在與規格識別碼相符的欄位名稱,且相關聯值符合規格的類型
規格已標記為選擇性,且在記錄中沒有找到任何對應的欄位名稱
只有在記錄類型為開放時,符合值才可包含並未列在欄位規格清單中的欄位名稱。
函式類型
任何函式類型都符合基本類型 function,此類型不會針對函式的型式參數或函式的傳回值施加任何限制。 自訂 function-type 值會用來針對符合函式值的簽章施加類型限制。
function-type:
function (parameter-specification-listopt)function-return-type
parameter-specification-list:
required-parameter-specification-list
required-parameter-specification-list , optional-parameter-specification-list
optional-parameter-specification-list
required-parameter-specification-list:
required-parameter-specification
required-parameter-specification , required-parameter-specification-list
required-parameter-specification:
parameter-specification
optional-parameter-specification-list:
optional-parameter-specification
optional-parameter-specification , optional-parameter-specification-list
optional-parameter-specification:
optionalparameter-specification
parameter-specification:
parameter-name parameter-type
function-return-type:
assertion
斷言:
asnullable-primitive-type
評估 function-type 的結果是一個類型值,其基本類型為 function。
下列範例示範宣告函式類型的語法:
type function (x as text) as number
type function (y as number, optional z as text) as any
若函式值其傳回類型與函式類型的傳回類型相容,且函式類型每個參數規格都與函式對應位置的型式參數相容,則函式值便符合函式類型。 若指定的 parameter-type 類型與型式參數類型相容,則參數規格便與型式參數相容,且若型式參數是選擇性的,則參數規格也會是選擇性的。
為了判斷函式類型是否符合,會忽略型式參數的名稱。
資料表類型
table-type 值會用來定義資料表值的結構。
table-type:
tablerow-type
row-type:
[field-specification-list]
評估 table-type 的結果是一個類型值,其基本類型為 table。
資料表的「資料列類型」會指定資料行名稱,並將資料表的資料行類型指定為封閉記錄類型。 所以,所有與 table 類型符合的資料表值,其資料列類型都會是 record 類型 (空白的開放式記錄類型)。 因此,table 類型是抽象類型,因為沒有任何資料表值的資料列類型是 table (但所有資料表值都擁有與 table 資料列類型相容的資料列類型)。 下列範例顯示資料表類型的建構:
type table [A = text, B = number, C = binary]
// a table type with three columns named A, B, and C
// of column types text, number, and binary, respectively
table-type 值也包含資料表值「索引鍵」的定義。 索引鍵是一組資料行名稱。 最多只能指定一個索引鍵作為資料表的「主索引鍵」。 (M 內,資料表索引鍵沒有語意意義。不過,外部資料源通常會在資料表上定義索引鍵,例如資料庫或 OData 摘要。Power Query使用重要資訊來改善進階功能的效能,例如跨來源聯結作業。)
標準程式庫函式 Type.TableKeys、Type.AddTableKey 和 Type.ReplaceTableKeys 分別可以用來取得資料表類型的索引鍵、將索引鍵新增到資料表類型,以及取代資料表類型的所有索引鍵。
Type.AddTableKey(tableType, {"A", "B"}, false)
// add a non-primary key that combines values from columns A and B
Type.ReplaceTableKeys(tableType, {})
// returns type value with all keys removed
可為 Null 的型別
針對任何 type T,可為 Null 的變體可以透過使用 nullable-type 來衍生:
nullable-type:
nullabletype
其結果是抽象類型,其允許 T 類型的值,或 null 值。
42 is nullable number // true null is
nullable number // true
T的 Ascription type nulltype nullable 會縮減為 或 typeT的描述。 (回想一下,可為 Null 的型別是抽象型別,而且沒有任何值可以直接屬於抽象類別型。)
Value.Type(42 as nullable number) // type number
Value.Type(null as nullable number) // type null
標準程式庫函式 Type.IsNullable 和 Type.NonNullable 可以用來測試類型的可為 Null 性,以及從該類型移除可為 Null 性。
下列項目適用 (針對任何 type T):
type T與type nullable T相容Type.NonNullable(type T)與type T相容
下列是成對的相等項目 (針對任何 type T):
type nullable any
any
Type.NonNullable(type any)
type anynonnull
type nullable none
type null
Type.NonNullable(type null)
type none
type nullable nullable T
type nullable T
Type.NonNullable(Type.NonNullable(type T))
Type.NonNullable(type T)
Type.NonNullable(type nullable T)
Type.NonNullable(type T)
type nullable (Type.NonNullable(type T))
type nullable T
值的歸屬類型
值的「歸屬類型」是值「宣告」符合的類型。 當值歸屬於某一類型時,只會進行有限的符合性檢查。 M 不會在可為 Null 的基本類型之外執行一致性檢查。 選擇使用類型定義比可為 Null 基本類型更複雜之類型的 M 程式作者,必須確保這類值符合這些類型。
您可使用程式庫函式 Value.ReplaceType 來將值歸屬至類型。 函式會傳回已歸屬類型的新值,如果新類型與值的原生基本類型不相容,則會引發錯誤。 特別是,當嘗試歸屬抽象類型 (例如 any) 時,函式會引發錯誤。
程式庫函式可根據輸入值的歸屬類型來選擇計算,並將複雜類型歸屬至結果。
您可使用程式庫函式 Value.Type 來取得值的歸屬類型。 例如:
Value.Type( Value.ReplaceType( {1}, type {number} )
// type {number}
類型等價和相容性
M 中並未定義類型等價。比較任意兩個類型值是否相等可能會也可能不會傳回 true。 但是,這兩種類型之間的關聯 (true 或是 false) 一律為相同。
指定類型和可為 Null 基本類型間的相容性可以透過程式庫函式 Type.Is 判斷,該函式接受任意類型值作為其第一個引數,並接受可為 Null 的基本類型值作為其第二個引數:
Type.Is(type text, type nullable text) // true
Type.Is(type nullable text, type text) // false
Type.Is(type number, type text) // false
Type.Is(type [a=any], type record) // true
Type.Is(type [a=any], type list) // false
M 中並未提供判斷指定類型與自訂類型是否相容的支援。
標準程式庫包含函式的集合,可從自訂類型擷取定義特性,因此仍然可以將特定相容性測試作為 M 運算式實作。 以下是一些範例;請參閱 M 程式庫規格以取得完整詳細資料。
Type.ListItem( type {number} )
// type number
Type.NonNullable( type nullable text )
// type text
Type.RecordFields( type [A=text, B=time] )
// [ A = [Type = type text, Optional = false],
// B = [Type = type time, Optional = false] ]
Type.TableRow( type table [X=number, Y=date] )
// type [X = number, Y = date]
Type.FunctionParameters(
type function (x as number, optional y as text) as number)
// [ x = type number, y = type nullable text ]
Type.FunctionRequiredParameters(
type function (x as number, optional y as text) as number)
// 1
Type.FunctionReturn(
type function (x as number, optional y as text) as number)
// type number