Udostępnij za pośrednictwem


Typy

Wartość typu to wartość, która klasyfikuje inne wartości. Wartość sklasyfikowana przez typ jest określana jako zgodna z tym typem. System typów M składa się z następujących rodzajów typów:

  • Typy pierwotne, które klasyfikują wartości pierwotne (binary, date, datetimedatetimezonedurationlistlogicalnullnumberrecordtexttimetype), a także zawierają wiele typów abstrakcyjnych (function, table, anyanynonnull i )none

  • Typy rekordów, które klasyfikują wartości rekordów na podstawie nazw pól i typów wartości

  • Typy list, które klasyfikują listy przy użyciu typu podstawowego pojedynczego elementu

  • Typy funkcji, które klasyfikują wartości funkcji na podstawie typów ich parametrów i zwracanych wartości

  • Typy tabel, które klasyfikują wartości tabeli na podstawie nazw kolumn, typów kolumn i kluczy

  • Typy dopuszczane wartości null, które klasyfikuje wartość null oprócz wszystkich wartości sklasyfikowanych przez typ podstawowy

  • Typy typów, które klasyfikują wartości, które są typami

Zestaw typów pierwotnych none Wszystkie wartości funkcji są zgodne z typem functionabstrakcyjnym , wszystkie wartości tabeli do typu tableabstrakcyjnego , wszystkie wartości typu abstrakcyjnego , wszystkie wartości anyinne niż null do typu anynonnullabstrakcyjnego , a nie wartości typu abstrakcyjnego none. Wyrażenie typu none musi zgłosić błąd lub zakończyć się niepowodzeniem, ponieważ nie można wygenerować żadnej wartości zgodnej z typem none. Należy pamiętać, że typy function pierwotne i table są abstrakcyjne, ponieważ żadna funkcja lub tabela nie jest bezpośrednio z tych typów, odpowiednio. Typy record pierwotne i list nie są abstrakcyjne, ponieważ reprezentują otwarty rekord bez zdefiniowanych pól i listę typów odpowiednio.

Wszystkie typy, które nie są elementami członkowskimi zamkniętego zestawu typów pierwotnych oraz ich odpowiedniki dopuszczające wartość null, są zbiorczo określane jako typy niestandardowe. Typy niestandardowe można zapisywać przy użyciu elementu type-expression:

wyrażenie-typ:
      wyrażenie-podstawowe

       type typ podstawowy
type:
      wyrażenie-podstawowe
      typ podstawowy
typ podstawowy:
      typ pierwotny
      typ rekordu
      typ listy
      typ funkcji
      typ tabeli
      typ dopuszczalny do wartości null
typ-pierwotny:
jeden z
      any anynonnull binary date datetime datetimezone duration function list logical
      none null number record table text time type

Nazwy typów pierwotnych to kontekstowe słowa kluczowe rozpoznawane tylko w kontekście typu . Użycie nawiasów w kontekście typu przenosi gramatykę z powrotem do kontekstu wyrażenia regularnego, co wymaga użycia słowa kluczowego typu, aby wrócić do kontekstu typu. Aby na przykład wywołać funkcję w kontekście typu , można użyć nawiasów:

type nullable ( Type.ForList({type number}) )   
// type nullable {number}

Nawiasy mogą również służyć do uzyskiwania dostępu do zmiennej, której nazwa zderza się z nazwą typu pierwotnego:

let  record = type [ A = any ]  in  type {(record)} 
// type {[ A = any ]}

W poniższym przykładzie zdefiniowano typ klasyfikujący listę liczb:

type { number }

Podobnie w poniższym przykładzie zdefiniowano typ niestandardowy, który klasyfikuje rekordy z obowiązkowymi polami o nazwie X i Y których wartości są liczbami:

type [ X = number, Y = number ]

Przypisany typ wartości jest uzyskiwany przy użyciu standardowej funkcji biblioteki Value.Type, jak pokazano w następujących przykładach:

Value.Type( 2 )                 // type number 
Value.Type( {2} )               // type list 
Value.Type( [ X = 1, Y = 2 ] )  // type record

Operator is służy do określania, czy typ wartości jest zgodny z danym typem, jak pokazano w następujących przykładach:

1 is number          // true 
1 is text            // false 
{2} is list          // true

Operator as sprawdza, czy wartość jest zgodna z danym typem, i zgłasza błąd, jeśli nie jest. W przeciwnym razie zwraca oryginalną wartość.

Value.Type( 1 as number )   // type number 
{2} as text                 // error, type mismatch

Należy pamiętać, że is operatory i as akceptują tylko typy pierwotne dopuszczające wartość null jako prawy operand. Język M nie zapewnia środków sprawdzania wartości pod kątem zgodności z typami niestandardowymi.

Typ X jest zgodny z typem Y , jeśli i tylko wtedy, gdy wszystkie wartości zgodne X również z Y. Wszystkie typy są zgodne z typem any i nie none są zgodne z typem none. Na poniższym wykresie przedstawiono relację zgodności. (Zgodność typu jest refleksyjna i przechodnia. Tworzy kratę z typem any u góry i typem none jako wartość dolną). Nazwy typów abstrakcyjnych są ustawiane kursywą.

Zgodność typów

Następujące operatory są definiowane dla wartości typów:

Operator Result
x = y Equal
x <> y Not equal
x ?? y Coalesce

Natywnym typem wartości typu jest typ typewewnętrzny .

Typy pierwotne

Typy w języku M tworzą rozłączną hierarchię zakorzenione w typie any, czyli typ, który klasyfikuje wszystkie wartości. Każda wartość języka M jest zgodna z dokładnie jednym podtypem pierwotnym .any Zamknięty zestaw typów pierwotnych pochodnych z typu any jest następujący:

  • type null, który klasyfikuje wartość null.
  • type logical, który klasyfikuje wartości true i false.
  • type number, który klasyfikuje wartości liczbowe.
  • type time, który klasyfikuje wartości czasu.
  • type date, który klasyfikuje wartości dat.
  • type datetime, który klasyfikuje wartości daty/godziny.
  • type datetimezone, który klasyfikuje wartości daty/godziny/strefy czasowej.
  • type duration, który klasyfikuje wartości czasu trwania.
  • type text, który klasyfikuje wartości tekstowe.
  • type binary, który klasyfikuje wartości binarne.
  • type type, który klasyfikuje wartości typów.
  • type list, który klasyfikuje wartości listy.
  • type record, który klasyfikuje wartości rekordów.
  • type table, który klasyfikuje wartości tabeli.
  • type function, który klasyfikuje wartości funkcji.
  • type anynonnull, który klasyfikuje wszystkie wartości z wyłączeniem wartości null.
  • type none, który klasyfikuje brak wartości.

Dowolny typ

Typ any jest abstrakcyjny, klasyfikuje wszystkie wartości w języku M, a wszystkie typy w języku M są zgodne z elementem any. Zmienne typu any mogą być powiązane ze wszystkimi możliwymi wartościami. Ponieważ any jest abstrakcyjna, nie można przypisać jej do wartości — to znaczy, że żadna wartość nie jest bezpośrednio typu any.

Typy list

Każda wartość, która jest listą, jest zgodna z typem listwewnętrznym , który nie nakłada żadnych ograniczeń na elementy w wartości listy.

typ listy:
       { typ elementu}
typ elementu:
      typ

Wynikiem oceny typu listy jest wartość typu listy, którego typ podstawowy to list.

W poniższych przykładach przedstawiono składnię deklarowania homogenicznych typów list:

type { number }        // list of numbers type 
     { record }        // list of records type
     {{ text }}        // list of lists of text values

Wartość jest zgodna z typem listy, jeśli wartość jest listą, a każdy element w tej wartości listy jest zgodny z typem elementu typu listy.

Typ elementu typu listy wskazuje granicę: wszystkie elementy zgodnej listy są zgodne z typem elementu.

Typy rekordów

Każda wartość, która jest rekordem, jest zgodna z rekordem typu wewnętrznego, który nie nakłada żadnych ograniczeń dotyczących nazw pól ani wartości w ramach wartości rekordu. Wartość typu rekordu służy do ograniczania zestawu prawidłowych nazw, a także typów wartości, które mogą być skojarzone z tymi nazwami.

typ rekordu:
       [ open-record-marker]
       [ opcja field-specification-list]
       [ field-specification-list , open-record-marker]
lista-specyfikacji pól:
      specyfikacja pola
      field-specification,field-specification-list
specyfikacja pola:

       optional opt-name field-type-specificationopt
specyfikacja typu pola:

       = typ-pola
typ-pola:
      type
open-record-marker:

      ...

Wynikiem oceny typu rekordu record

W poniższych przykładach przedstawiono składnię deklarowania typów rekordów:

type [ X = number, Y = number] 
type [ Name = text, Age = number ]
type [ Title = text, optional Description = text ] 
type [ Name = text, ... ]

Typy rekordów są domyślnie zamykane , co oznacza, że dodatkowe pola, które nie znajdują się na liście pólpoznania , nie mogą być obecne w zgodnych wartościach. Uwzględnienie znacznika openrecord-w typie rekordu deklaruje, że typ ma być otwarty, co zezwala na pola, które nie znajdują się na liście specyfikacji pola. Następujące dwa wyrażenia są równoważne:

type record   // primitive type classifying all records 
type [ ... ]  // custom type classifying all records

Wartość jest zgodna z typem rekordu, jeśli wartość jest rekordem, a każda specyfikacja pola w typie rekordu jest satysfakcjonująca. Specyfikacja pola jest spełniona, jeśli którakolwiek z następujących wartości jest prawdziwa:

  • Nazwa pola pasująca do identyfikatora specyfikacji istnieje w rekordzie, a skojarzona wartość jest zgodna z typem specyfikacji

  • Specyfikacja jest oznaczona jako opcjonalna i nie można odnaleźć odpowiedniej nazwy pola w rekordzie

Zgodna wartość może zawierać nazwy pól, które nie są wymienione na liście specyfikacji pól, jeśli typ rekordu jest otwarty i tylko wtedy, gdy typ rekordu jest otwarty.

Typy funkcji

Każda wartość funkcji jest zgodna z typem functionpierwotnym , który nie nakłada żadnych ograniczeń dotyczących typów parametrów formalnych funkcji lub zwracanej wartości funkcji. Niestandardowa wartość typu funkcji służy do umieszczania ograniczeń typu dla podpisów zgodnych wartości funkcji.

typ funkcji:
       function ( parametr-specification-listopt)function-return-type
parametr-specification-list:
      required-parameter-specification-list
      required-parameter-specification-list
,optional-parameter-specification-list
      opcjonalna lista-specyfikacji parametrów
required-parameter-specification-list:
      required-parameter-specification
      required-parameter-specification
,required-parameter-specification-list
required-parameter-specification:
      specyfikacja parametrów
optional-parameter-specification-list:
      opcjonalna specyfikacja parametrów
      optional-parameter-specification
,optional-parameter-specification-list
opcjonalna specyfikacja parametrów:

       optional specyfikacja parametrów
specyfikacja parametrów:
      parametr-nazwa parametru typ-parametru
funkcja-return-type:
      assertion
twierdzenie:

       as typ-pierwotny dopuszczany do wartości null

Wynikiem oceny typu funkcji jest wartość typu, którego typ podstawowy to function.

W poniższych przykładach przedstawiono składnię deklarowania typów funkcji:

type function (x as text) as number 
type function (y as number, optional z as text) as any

Wartość funkcji jest zgodna z typem funkcji, jeśli zwracany typ wartości funkcji jest zgodny z zwracanym typem typu funkcji, a każda specyfikacja parametru typu funkcji jest zgodna z pozycjonalnie odpowiadającym mu parametrem formalnym funkcji. Specyfikacja parametru jest zgodna z parametrem formalnym, jeśli określony typ parametru jest zgodny z typem parametru formalnego, a specyfikacja parametru jest opcjonalna, jeśli parametr formalny jest opcjonalny.

Nazwy parametrów formalnych są ignorowane na potrzeby określania zgodności typu funkcji.

Określenie parametru jako opcjonalnego powoduje, że jego typ jest dopuszczający wartość null. Następujące typy funkcji tworzą identyczne typy funkcji:

type function (optional x as text) as any
type function (optional x as nullable text) as any

Typy tabel

Wartość typu tabeli służy do definiowania struktury wartości tabeli.

typ tabeli:
       table typ wiersza
typ wiersza:

       [ opcja field-specification-list]

Wynikiem oceny typu tabeli jest wartość typu, którego typ podstawowy to table.

Typ wiersza tabeli określa nazwy kolumn i typy kolumn tabeli jako typ zamkniętego rekordu. Aby wszystkie wartości tabeli były zgodne z typem , jego typ tablewiersza jest typem record (pustym typem otwartego rekordu). W związku z tym tabela typów jest abstrakcyjna, ponieważ żadna wartość tabeli nie może mieć typu wiersza typu table(ale wszystkie wartości tabeli mają typ wiersza zgodny z typem tablewiersza typu). W poniższym przykładzie przedstawiono konstrukcję typu tabeli:

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

Wartość typu tabeli zawiera również definicję kluczy wartości tabeli. Klucz to zestaw nazw kolumn. Co najwyżej jeden klucz można wyznaczyć jako klucz podstawowy tabeli. (W języku M klucze tabeli nie mają znaczenia semantycznego. Jednak w przypadku zewnętrznych źródeł danych, takich jak bazy danych lub źródła danych OData, typowe jest definiowanie kluczy w tabelach. Dodatek Power Query używa kluczowych informacji w celu zwiększenia wydajności zaawansowanych funkcji, takich jak operacje sprzężenia krzyżowego).

Standardowe funkcje Type.TableKeysbiblioteki , Type.AddTableKeyi Type.ReplaceTableKeys mogą służyć do uzyskiwania kluczy typu tabeli, dodawania klucza do typu tabeli i zastępowania wszystkich kluczy typu tabeli.

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

Typy dopuszczające wartości null

W przypadku dowolnego type Twariantu dopuszczalnego wartości null można uzyskać przy użyciu typu dopuszczalnego wartości null:

typ dopuszczalny do wartości null:
       nullable typ

Wynik jest typem abstrakcyjnym, który zezwala na wartości typu T lub wartości null.

42 is nullable number             // true null is
nullable number                   // true

Ascription T type nullable zmniejsza się do deskrypcji type null lub typeT. (Pamiętaj, że typy dopuszczające wartość null są abstrakcyjne i żadna wartość nie może być bezpośrednio typu abstrakcyjnego).

Value.Type(42 as nullable number)       // type number
Value.Type(null as nullable number)     // type null

Standardowe funkcje Type.IsNullable biblioteki i Type.NonNullable mogą służyć do testowania typu pod kątem wartości null i usuwania wartości null z typu.

Następująca blokada (dla dowolnego elementu type T):

  • type T jest zgodny z type nullable T
  • Type.NonNullable(type T) jest zgodny z type T

Poniżej przedstawiono odpowiedniki parowania (dla dowolnego type Telementu ):

    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

Przypisany typ wartości

Przypisany typ wartości to typ, do którego zadeklarowano zgodność wartości.

Wartość może być przypisana do typu przy użyciu funkcji Value.ReplaceTypebiblioteki . Ta funkcja zwraca nową wartość z przypisanym typem lub zgłasza błąd, jeśli nowy typ jest niezgodny z wartością.

Gdy wartość jest przypisana do typu, występuje tylko ograniczone sprawdzanie zgodności:

  • Typ, który jest przypisany, musi być nie abstrakcyjny, niepusty i zgodny z wewnętrznym (natywnym) typem pierwotnym wartości.
  • Gdy typ niestandardowy definiujący strukturę jest przypisywany, musi być zgodny ze strukturą wartości.
    • W przypadku rekordów: typ musi być zamknięty, musi zdefiniować tę samą liczbę pól co wartość i nie może zawierać żadnych pól opcjonalnych. (Nazwy pól i typy pól typu zastąpią te, które są obecnie skojarzone z rekordem. Jednak istniejące wartości pól nie będą sprawdzane względem nowych typów pól.
    • W przypadku tabel: typ musi definiować tę samą liczbę kolumn co wartość. (Nazwy kolumn i typy kolumn typu zastąpią te, które są obecnie skojarzone z tabelą. Jednak istniejące wartości kolumn nie będą sprawdzane względem nowych typów kolumn).
    • W przypadku funkcji: typ musi definiować tę samą liczbę wymaganych parametrów, a także taką samą liczbę parametrów opcjonalnych, jak wartość. (Parametr typu i asercji zwracanych, a także jego nazwy parametrów, zastąpi te skojarzone z bieżącym typem wartości funkcji. Jednak nowe asercji nie będą miały wpływu na rzeczywiste zachowanie funkcji).
    • W przypadku list: wartość musi być listą. (Jednak istniejące elementy listy nie będą sprawdzane względem nowego typu elementu).

Funkcje biblioteki mogą zdecydować się na obliczenia i przypisanie typów złożonych do wyników na podstawie przypisanych typów wartości wejściowych.

Przypisany typ wartości można uzyskać przy użyciu funkcji Value.Typebiblioteki . Na przykład:

Value.Type( Value.ReplaceType( {1}, type {number} ) 
// type {number}

Równoważność typów i zgodność

Równoważność typów nie jest zdefiniowana w języku M. Implementacja języka M może opcjonalnie użyć własnych reguł do przeprowadzania porównań równości między wartościami typów. Porównywanie dwóch wartości typu równości powinno być obliczane, true jeśli są one uważane za identyczne przez implementację i false w przeciwnym razie. W obu przypadkach zwracana odpowiedź musi być spójna, jeśli te same dwie wartości są wielokrotnie porównywane. Należy pamiętać, że w ramach danej implementacji porównanie niektórych identycznych wartości typu (takich jak (type text) = (type text)) może zwracać truewartość , porównując inne (takie jak (type [a = text]) = (type [a = text])) może nie.

Zgodność między danym typem a typem pierwotnym dopuszczanym do wartości null można określić przy użyciu funkcji Type.Isbiblioteki , która akceptuje dowolną wartość typu jako pierwszą i nullable wartość typu pierwotnego jako drugi argument:

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

W języku M nie ma obsługi określania zgodności danego typu z typem niestandardowym.

Biblioteka standardowa zawiera kolekcję funkcji w celu wyodrębnienia definiowania cech z typu niestandardowego, więc określone testy zgodności można zaimplementować jako wyrażenia języka M. Poniżej przedstawiono kilka przykładów. Aby uzyskać szczegółowe informacje, zapoznaj się ze specyfikacją biblioteki 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