Partilhar via


Processamento de Erros

O resultado da avaliação de uma expressão M produz um dos seguintes resultados:

  • Um único valor é produzido.

  • Um erro é gerado, indicando que o processo de avaliação da expressão não poderia produzir um valor. Um erro contém um único valor de registro que pode ser usado para fornecer informações adicionais sobre o que causou a avaliação incompleta.

Os erros podem ser gerados a partir de uma expressão e podem ser tratados a partir de uma expressão.

Suscitar erros

A sintaxe para gerar um erro é a seguinte:

expressão de aumento de erro:
      error expressão

Os valores de texto podem ser usados como abreviatura para valores de erro. Por exemplo:

error "Hello, world" // error with message "Hello, world"

Os valores de erro completos são registros e podem ser construídos usando a Error.Record função:

error Error.Record("FileNotFound", "File my.txt not found",
     "my.txt")

A expressão acima é equivalente a:

error [ 
    Reason = "FileNotFound", 
    Message = "File my.txt not found", 
    Detail = "my.txt" 
]

Gerar um erro fará com que a avaliação de expressão atual seja interrompida e a pilha de avaliação de expressão será desenrolada até que ocorra uma das seguintes situações:

  • Um campo de registro, membro de seção ou variável let — coletivamente: uma entrada — é alcançado. A entrada é marcada como tendo um erro, o valor do erro é salvo com essa entrada e, em seguida, propagado. Qualquer acesso subsequente a essa entrada causará um erro idêntico a ser gerado. Outras entradas do registro, seção ou expressão let não são necessariamente afetadas (a menos que acessem uma entrada marcada anteriormente como tendo um erro).

  • A expressão de nível superior é atingida. Nesse caso, o resultado da avaliação da expressão de nível superior é um erro em vez de um valor.

  • Chega-se a uma try expressão. Nesse caso, o erro é capturado e retornado como um valor.

Processar erros

Uma expressão de manipulação de erros (conhecida informalmente como "expressão try") é usada para lidar com um erro:

error-handling-expression:
      tryopt pelo manipuladorde erros de expressão protegida
Expressão-protegida:
      expressão
manipulador de erros:
      cláusula contrária
      Cláusula de captura
cláusula contrária:

      otherwiseexpressão-padrão
expressão-padrão:
      expressão
Cláusula de captura:
      catchFunção de captura
Função de captura:
      (nome-parâmetroopt =>) função-corpo

O seguinte vale ao avaliar uma expressão de manipulação de erros sem um manipulador de erros:

  • Se a avaliação da expressão protegida não resultar em um erro e produzir um valor x, o valor produzido pela expressão de manipulação de erros será um registro da seguinte forma:
    [ HasErrors = false, Value = x ]
  • Se a avaliação da expressão protegida gerar um valor de erro e, o resultado da expressão de tratamento de erros será um registro da seguinte forma:
    [ HasErrors = true, Error = e ]

O seguinte vale ao avaliar uma expressão de manipulação de erros com um manipulador de erros:

  • A expressão protegida deve ser avaliada antes do manipulador de erros.

  • O manipulador de erros deve ser avaliado se e somente se a avaliação da expressão protegida gerar um erro.

  • Se a avaliação da expressão protegida gerar um erro, o valor produzido pela expressão de manipulação de erros é o resultado da avaliação do manipulador de erros.

  • Os erros gerados durante a avaliação do manipulador de erros são propagados.

  • Quando o manipulador de erros que está sendo avaliado é uma cláusula catch, a função catch-é invocada. Se essa função aceitar um parâmetro, o valor do erro será passado como seu valor.

O exemplo a seguir ilustra uma expressão de manipulação de erros em um caso em que nenhum erro é gerado:

let
    x = try "A"
in
    if x[HasError] then x[Error] else x[Value] 
// "A"

O exemplo a seguir mostra como gerar um erro e, em seguida, manipulá-lo:

let
    x = try error "A" 
in
    if x[HasError] then x[Error] else x[Value] 
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

O exemplo anterior pode ser reescrito com menos sintaxe usando uma cláusula catch-com uma função catch-que aceita um parâmetro:

let
    x = try error "A" catch (e) => e
in
    x
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

Uma cláusula de outra forma pode ser usada para substituir erros manipulados por uma expressão try por um valor alternativo:

try error "A" otherwise 1 
// 1

Uma cláusula catch-com uma função catch-parâmetro zero é efetivamente uma sintaxe alternativa mais longa para uma cláusula de outra forma:

try error "A" catch () => 1 
// 1

Se o manipulador de erros também gerar um erro, toda a expressão try também gera:

try error "A" otherwise error "B" 
// error with message "B"
try error "A" catch () => error "B" 
// error with message "B"
try error "A" catch (e) => error "B" 
// error with message "B"

Erros nos inicializadores de registro e permissão

O exemplo a seguir mostra um inicializador de registro com um campo A que gera um erro e é acessado por dois outros campos B e C. O campo B não lida com o erro gerado pelo A, mas C o faz. O campo D final não acessa A e, portanto, não é afetado pelo erro em A.

[ 
    A = error "A", 
    B = A + 1,
    C = let x =
            try A in
                if not x[HasError] then x[Value]
                else x[Error], 
    D = 1 + 1 
]

O resultado da avaliação da expressão acima é:

[ 
    A = // error with message "A" 
    B = // error with message "A" 
    C = "A", 
    D = 2 
]

O tratamento de erros em M deve ser realizado próximo à causa dos erros para lidar com os efeitos da inicialização de campo preguiçoso e avaliações de fechamento diferido. O exemplo a seguir mostra uma tentativa malsucedida de manipular um erro usando uma try expressão:

let
    f = (x) => [ a = error "bad", b = x ],
    g = try f(42) otherwise 123
in 
    g[a]  // error "bad"

Neste exemplo, a definição g destinava-se a lidar com o erro gerado ao chamar f. No entanto, o erro é gerado por um inicializador de campo que só é executado quando necessário e, portanto, depois que o registro foi retornado de f e passado pela try expressão.

Erro não implementado

Enquanto uma expressão está sendo desenvolvida, um autor pode querer deixar de fora a implementação para algumas partes da expressão, mas ainda pode querer ser capaz de executar a expressão. Uma maneira de lidar com esse caso é gerar um erro para as partes não implementadas. Por exemplo:

(x, y) =>
     if x > y then
         x - y
     else
         error Error.Record("Expression.Error", 
            "Not Implemented")

O símbolo de reticências (...) pode ser usado como um atalho para error.

expressão não implementada:
      ...

Por exemplo, o seguinte é equivalente ao exemplo anterior:

(x, y) => if x > y then x - y else ...