Ler em inglês

Partilhar via


Tipos

Um valor de tipo é um valor que classifica outros valores. Diz-se que um valor classificado por um tipo está em conformidade com esse tipo. O sistema do tipo M consiste nos seguintes tipos de tipos:

  • Tipos primitivos, que classificam valores primitivos (binary, date, datetime, datetimezone, duration, list, numbertextlogicalrecordtypenulltime) e também incluem vários tipos abstratos (function, table, anyanynonnull , e )none

  • Tipos de registro, que classificam valores de registro com base em nomes de campo e tipos de valor

  • Tipos de lista, que classificam listas usando um único tipo de base de item

  • Tipos de função, que classificam valores de função com base nos tipos de seus parâmetros e valores de retorno

  • Tipos de tabela, que classificam valores de tabela com base em nomes de coluna, tipos de coluna e chaves

  • Tipos anuláveis, que classifica o valor null além de todos os valores classificados por um tipo base

  • Tipos de tipo, que classificam valores que são tipos

O conjunto de tipos primitivos inclui os tipos de valores primitivos e vários tipos abstratos, que são tipos que não classificam exclusivamente nenhum valor: function, table, anyanynonnull e none. Todos os valores de função estão de acordo com o tipo functionabstrato, todos os valores de tabela para o tipo tableabstrato, todos os valores para o tipo anyabstrato, todos os valores não nulos para o tipo anynonnullabstrato e nenhum valor para o tipo noneabstrato. Uma expressão de tipo none deve gerar um erro ou não terminar, uma vez que nenhum valor pode ser produzido em conformidade com o tipo none. Note que os tipos function primitivos e table são abstratos porque nenhuma função ou tabela é diretamente desses tipos, respectivamente. Os tipos record primitivos e list não são abstratos porque representam um registro aberto sem campos definidos e uma lista de tipo qualquer, respectivamente.

Todos os tipos que não são membros do conjunto fechado de tipos primitivos mais suas contrapartes anuláveis são coletivamente referidos como tipos personalizados. Os tipos personalizados podem ser escritos usando um type-expression:

tipo-expressão:
      expressão-primária

      typetipo-primário
type:
      expressão-primária
      tipo-primário
tipo primário:
      primitivo-tipo
      tipo de registo
      tipo de lista
      tipo de função
      tipo de tabela
      tipo nulo
primitivo-tipo:
um dos
      any anynonnull binary date datetime datetimezone duration function list logical
      none null number record table text time type

Os nomes de tipo primitivo são palavras-chave contextuais reconhecidas apenas em um contexto de tipo . O uso de parênteses em um contexto de tipo move a gramática de volta para um contexto de expressão regular, exigindo o uso da palavra-chave type para voltar a um contexto de tipo. Por exemplo, para invocar uma função em um contexto de tipo , parênteses podem ser usados:

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

Parênteses também podem ser usados para acessar uma variável cujo nome colide com um nome de tipo primitivo:

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

O exemplo a seguir define um tipo que classifica uma lista de números:

type { number }

Da mesma forma, o exemplo a seguir define um tipo personalizado que classifica registros com campos obrigatórios nomeados X e Y cujos valores são números:

type [ X = number, Y = number ]

O tipo atribuído de um valor é obtido usando a função de biblioteca padrão Value.Type, conforme mostrado nos exemplos a seguir:

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

O is operador é usado para determinar se o tipo de um valor é compatível com um determinado tipo, como mostrado nos exemplos a seguir:

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

O as operador verifica se o valor é compatível com o tipo dado e gera um erro se não for. Caso contrário, ele retorna o valor original.

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

Observe que os is operadores e as só aceitam tipos primitivos anuláveis como seu operando direito. M não fornece meios para verificar a conformidade dos valores com os tipos personalizados.

Um tipo X é compatível com um tipo Y se e somente se todos os valores que estão em conformidade também X estiverem em conformidade com Y. Todos os tipos são compatíveis com o tipo any e nenhum tipo (mas none ele próprio) é compatível com o tipo none. O gráfico a seguir mostra a relação de compatibilidade. (A compatibilidade de tipo é reflexiva e transitiva. Ele forma uma rede com tipo any como o valor superior e tipo none como o valor inferior.) Os nomes dos tipos abstratos são definidos em itálico.

Compatibilidade de tipos

Os seguintes operadores são definidos para valores de tipo:

Operador Result
x = y Igual
x <> y Não é igual a
x ?? y Coalesce

O tipo nativo de valores de tipo é o tipo typeintrínseco .

Tipos primitivos

Os tipos na linguagem M formam uma hierarquia disjunta enraizada no tipo any, que é o tipo que classifica todos os valores. Qualquer valor M está em conformidade com exatamente um subtipo primitivo de any. O conjunto fechado de tipos primitivos derivados do tipo any são os seguintes:

  • type null, que classifica o valor nulo.
  • type logical, que classifica os valores verdadeiro e falso.
  • type number, que classifica os valores numéricos.
  • type time, que classifica os valores de tempo.
  • type date, que classifica os valores de data.
  • type datetime, que classifica os valores datetime.
  • type datetimezone, que classifica os valores de datetimezone.
  • type duration, que classifica os valores de duração.
  • type text, que classifica os valores do texto.
  • type binary, que classifica valores binários.
  • type type, que classifica os valores de tipo.
  • type list, que classifica os valores da lista.
  • type record, que classifica os valores de registo.
  • type table, que classifica os valores da tabela.
  • type function, que classifica os valores das funções.
  • type anynonnull, que classifica todos os valores excluindo null.
  • type none, que não classifica valores.

Qualquer tipo

O tipo any é abstrato, classifica todos os valores em M e todos os tipos em M são compatíveis com any. As variáveis do tipo any podem ser vinculadas a todos os valores possíveis. Uma vez any que é abstrato, não pode ser atribuído a valores, ou seja, nenhum valor é diretamente do tipo any.

Tipos de lista

Qualquer valor que seja uma lista está em conformidade com o tipo listintrínseco , que não coloca nenhuma restrição sobre os itens dentro de um valor de lista.

tipo de lista:
      { tipo de item }
tipo de artigo:
      tipo

O resultado da avaliação de um tipo de lista é um valor de tipo de lista cujo tipo base é list.

Os exemplos a seguir ilustram a sintaxe para declarar tipos de lista homogênea:

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

Um valor estará em conformidade com um tipo de lista se o valor for uma lista e cada item nesse valor de lista estiver em conformidade com o tipo de item do tipo de lista.

O tipo de item de um tipo de lista indica um limite: todos os itens de uma lista em conformidade estão em conformidade com o tipo de item.

Tipos de Registo

Qualquer valor que seja um registro está em conformidade com o registro de tipo intrínseco, que não coloca nenhuma restrição sobre os nomes de campo ou valores dentro de um valor de registro. Um valor de tipo de registro é usado para restringir o conjunto de nomes válidos, bem como os tipos de valores que podem ser associados a esses nomes.

tipo de registo:
      [marcador de registo aberto ]
      [ field-specification-listopt ]
      [ field-specification-list , marcador de registo aberto ]
campo-especificação-lista:
      especificação de campo
      campo-especificação-campo-especificação-lista,
Especificação do campo:

      optional opt campo-nome-campo-tipo-especificaçãoopt
especificação do tipo de campo:

      =tipo de campo
tipo de campo:
      tipo
marcador de registo aberto:

      ...

O resultado da avaliação de um tipo de registro é um valor de tipo cujo tipo base é record.

Os exemplos a seguir ilustram a sintaxe para declarar tipos de registro:

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

Os tipos de registro são fechados por padrão, o que significa que campos adicionais não presentes na lista de especificações de campo não podem estar presentes em valores conformes. A inclusão do marcador openrecord no tipo de registro declara que o tipo está aberto, o que permite campos não presentes na lista de especificações de campo. As duas expressões seguintes são equivalentes:

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

Um valor estará em conformidade com um tipo de registro se o valor for um registro e cada especificação de campo no tipo de registro for satisfeita. Uma especificação de campo será satisfeita se qualquer uma das seguintes opções for verdadeira:

  • Existe um nome de campo correspondente ao identificador da especificação no registo e o valor associado está em conformidade com o tipo da especificação

  • A especificação é marcada como opcional e nenhum nome de campo correspondente é encontrado no registro

Um valor conforme pode conter nomes de campos não listados na lista de especificações de campo se e somente se o tipo de registro estiver aberto.

Tipos de função

Qualquer valor de função está em conformidade com o tipo functionprimitivo , que não coloca quaisquer restrições sobre os tipos de parâmetros formais da função ou o valor de retorno da função. Um valor de tipo de função personalizado é usado para colocar restrições de tipo nas assinaturas de valores de função conformes.

tipo de função:
      function ( parâmetro-especificação-listaopt )função-retorno-tipo
parameter-specification-list:
      required-parameter-specification-list
      required-parameter-specification-list
, opcional-parameter-specification-list
      opcional-parâmetro-especificação-lista
required-parameter-specification-list:
      especificação do parâmetro necessário
      required-parameter-specification
, required-parameter-specification-list
especificação do parâmetro necessário:
      parâmetro-especificação
opcional-parâmetro-especificação-lista:
      opcional-parâmetro-especificação
      opcional-parâmetro-especificação
, opcional-parâmetro-especificação-lista
opcional-parâmetro-especificação:

      optionalparâmetro-especificação
parâmetro-especificação:
      parameter-name parameter-type
função-retorno-tipo:
      assertion
asserção:

      as nullable-primitive-type

O resultado da avaliação de um tipo de função é um valor de tipo cujo tipo base é function.

Os exemplos a seguir ilustram a sintaxe para declarar tipos de função:

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

Um valor de função está em conformidade com um tipo de função se o tipo de retorno do valor da função for compatível com o tipo de retorno do tipo de função e cada especificação de parâmetro do tipo de função for compatível com o parâmetro formal correspondente posicionalmente da função. Uma especificação de parâmetro é compatível com um parâmetro formal se o tipo de parâmetro especificado for compatível com o tipo do parâmetro formal e a especificação do parâmetro for opcional se o parâmetro formal for opcional.

Os nomes de parâmetros formais são ignorados para determinar a conformidade do tipo de função.

Especificar um parâmetro como opcional implicitamente torna seu tipo anulável. Os seguintes criam tipos de função idênticos:

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

Tipos de tabela

Um valor de tipo de tabela é usado para definir a estrutura de um valor de tabela.

tipo de tabela:
      tabletipo de linha
tipo de linha:

      [ field-specification-listopt ]

O resultado da avaliação de um tipo de tabela é um valor de tipo cujo tipo base é table.

O tipo de linha de uma tabela especifica os nomes de coluna e os tipos de coluna da tabela como um tipo de registro fechado. Para que todos os valores da tabela estejam em conformidade com o tipo table, seu tipo de linha é tipo record (o tipo de registro aberto vazio). Assim, a tabela de tipo é abstrata, uma vez que nenhum valor de tabela pode ter o tipo de linha do tipo table(mas todos os valores da tabela têm um tipo de linha que é compatível com o tipo de linha do tipo table). O exemplo a seguir mostra a construção de um tipo de tabela:

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

Um valor de tipo de tabela também carrega a definição das chaves de um valor de tabela. Uma chave é um conjunto de nomes de coluna. No máximo, uma chave pode ser designada como chave primária da tabela. (Dentro de M, as chaves de tabela não têm significado semântico. No entanto, é comum que fontes de dados externas, como bancos de dados ou feeds OData, definam chaves sobre tabelas. O Power Query utiliza informações importantes para melhorar o desempenho de funcionalidades avançadas, tais como operações de junção entre fontes.)

A biblioteca padrão funciona Type.TableKeys, Type.AddTableKeye Type.ReplaceTableKeys pode ser usada para obter as chaves de um tipo de tabela, adicionar uma chave a um tipo de tabela e substituir todas as chaves de um tipo de tabela, respectivamente.

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

Tipos anuláveis

Para qualquer type T, uma variante anulável pode ser derivada usando nullable-type:

nullable-type:
      nullabletipo

O resultado é um tipo abstrato que permite valores do tipo T ou do valor null.

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

A atribuição de type nullable T reduz-se à atribuição de type null ou type T. (Lembre-se de que os tipos anuláveis são abstratos e nenhum valor pode ser diretamente do tipo abstrato.)

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

A biblioteca padrão funciona Type.IsNullable e Type.NonNullable pode ser usada para testar um tipo quanto à anulabilidade e para remover a anulabilidade de um tipo.

A seguinte retenção (para qualquer type T):

  • type T é compatível com type nullable T
  • Type.NonNullable(type T) é compatível com type T

Os seguintes são equivalentes em pares (para qualquer 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

Tipo atribuído de um valor

O tipo atribuído a um valor é o tipo ao qual um valor é declarado conforme.

Um valor pode ser atribuído um tipo usando a função Value.ReplaceTypede biblioteca . Essa função retorna um novo valor com o tipo atribuído ou gera um erro se o novo tipo for incompatível com o valor.

Quando um valor é atribuído a um tipo, ocorre apenas uma verificação de conformidade limitada:

  • O tipo que está sendo atribuído deve ser não-abstrato, não anulável e compatível com o tipo primitivo intrínseco (nativo) do valor.
  • Quando um tipo personalizado que define a estrutura é atribuído, ele deve corresponder à estrutura do valor.
    • Para registros: O tipo deve ser fechado, deve definir o mesmo número de campos que o valor e não deve conter nenhum campo opcional. (Os nomes de campo e os tipos de campo do tipo substituirão os atualmente associados ao registro. No entanto, os valores de campo existentes não serão verificados em relação aos novos tipos de campo.)
    • Para tabelas: O tipo deve definir o mesmo número de colunas que o valor. (Os nomes de coluna e os tipos de coluna do tipo substituirão os atualmente associados à tabela. No entanto, os valores de coluna existentes não serão verificados em relação aos novos tipos de coluna.)
    • Para funções: O tipo deve definir o mesmo número de parâmetros necessários, bem como o mesmo número de parâmetros opcionais, como o valor. (O parâmetro do tipo e as asserções de retorno, bem como seus nomes de parâmetro, substituirão aqueles associados ao tipo atual do valor da função. No entanto, as novas asserções não terão efeito sobre o comportamento real da função.)
    • Para listas: O valor deve ser uma lista. (No entanto, os itens de lista existentes não serão verificados em relação ao novo tipo de item.)

As funções de biblioteca podem optar por calcular e atribuir tipos complexos aos resultados com base nos tipos atribuídos dos valores de entrada.

O tipo atribuído de um valor pode ser obtido usando a função Value.Typebiblioteca . Por exemplo:

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

Equivalência de tipo e compatibilidade

A equivalência de tipo não é definida em M. Uma implementação M pode, opcionalmente, optar por usar suas próprias regras para realizar comparações de igualdade entre valores de tipo. Comparando dois valores de tipo para igualdade deve avaliar true se eles são considerados idênticos pela implementação, e false de outra forma. Em ambos os casos, a resposta retornada deve ser consistente se os mesmos dois valores forem repetidamente comparados. Observe que, dentro de uma determinada implementação, a comparação de alguns valores de tipo idênticos (como (type text) = (type text)) pode retornar, enquanto a comparação de outros (como (type [a = text]) = (type [a = text])) pode não retornartrue.

A compatibilidade entre um determinado tipo e um tipo primitivo anulável pode ser determinada usando a função Type.Islibrary , que aceita um valor de tipo arbitrário como seu primeiro e um valor de tipo primitivo anulável como seu segundo argumento:

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

Não há suporte em M para determinar a compatibilidade de um determinado tipo com um tipo personalizado.

A biblioteca padrão inclui uma coleção de funções para extrair as características definidoras de um tipo personalizado, para que testes de compatibilidade específicos possam ser implementados como expressões M. Seguem-se alguns exemplos; consulte a especificação da biblioteca M para obter todos os detalhes.

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