Поделиться через


Обработка ошибок

Результат вычисления выражения M приводит к одному из следующих результатов:

  • Создается одно значение.

  • Возникает ошибка, указывающая, что процесс оценки выражения не удалось создать значение. Ошибка содержит одно значение записи, которое можно использовать для предоставления дополнительных сведений о том, что вызвало неполное вычисление.

Ошибки могут возникать из выражения и обрабатываться из выражения.

Создание ошибок

Синтаксис для создания ошибки выглядит следующим образом:

выражение error-raising-expression:
      error выражение

Текстовые значения можно использовать в качестве сокращенных значений ошибок. Например:

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

Полные значения ошибок — это записи и можно создать с помощью Error.Record функции:

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

Приведенное выше выражение эквивалентно следующему:

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

При возникновении ошибки текущая оценка выражений будет остановлена, и стек вычислений выражений будет отсохнет до тех пор, пока не произойдет одно из следующих действий:

  • Пока не будет достигнуто поле записи, элемент раздела или переменная let — в совокупности — запись. Запись помечена как ошибка, значение ошибки сохраняется с этой записью, а затем распространяется. Любой последующий доступ к этой записи приведет к возникновению идентичной ошибки. Другие записи записи, раздела или выражения пусть не обязательно затронуты (если они не получают доступ к записи, помеченной как ошибка).

  • Достигается выражение верхнего уровня. В этом случае результат оценки выражения верхнего уровня является ошибкой вместо значения.

  • try Достигается выражение. В этом случае ошибка фиксируется и возвращается в качестве значения.

Обработка ошибок

Выражение обработки ошибок (неофициально известное как "выражение try") используется для обработки ошибки:

Выражение error-handling-expression:
      tryВыборобработчика ошибок защищенного выражения
защищенное-выражение:
      выражение
Обработчик ошибок:
      Предложение в противном случае
      предложение catch-
предложение-otherwise:

      otherwiseвыражение по умолчанию
выражение по умолчанию:
      выражение
предложение catch-:
      catchcatch-function
catch-function:
      (параметр-nameopt) => function-body

При оценке выражения обработки ошибок без обработчика ошибок следует учитывать следующее:

  • Если оценка защищенного выражения не приводит к ошибке и создает значение x, значение, созданное выражением обработки ошибок, является записью следующей формы:
    [ HasErrors = false, Value = x ]
  • Если оценка защищенного выражения вызывает значение ошибки e, результат выражения обработки ошибок является записью следующей формы:
    [ HasErrors = true, Error = e ]

При оценке выражения обработки ошибок с помощью обработчика ошибок содержится следующее:

  • Перед обработчиком ошибок необходимо оценить защищенное выражение.

  • Обработчик ошибок должен оцениваться только в том случае, если оценка защищенного выражения вызывает ошибку.

  • Если оценка защищенного выражения вызывает ошибку, значение, созданное выражением обработки ошибок, является результатом оценки обработчика ошибок.

  • Ошибки, возникающие во время оценки обработчика ошибок, распространяются.

  • Когда вычисляемый обработчик ошибок является предложением catch-, вызывается функция catch. Если эта функция принимает параметр, значение ошибки будет передано в качестве значения.

В следующем примере показано выражение обработки ошибок в случае, когда ошибка не возникает:

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

В следующем примере показано создание ошибки, а затем обработка ошибки:

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

Предыдущий пример можно переписать с меньшим синтаксисом с помощью предложения catch-с функцией catch, которая принимает параметр:

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

Предложение в противном случае можно использовать для замены ошибок, обрабатываемых выражением try, альтернативным значением:

try error "A" otherwise 1 
// 1

Предложение catch-с нулевым параметром catch-function является более длинным альтернативным синтаксисом для предложения в противном случае:

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

Если обработчик ошибок также вызывает ошибку, то выполняется все выражение try:

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"

Ошибки в записи и разрешить инициализаторам

В следующем примере показан инициализатор записей с полем A , которое вызывает ошибку и обращается к двум другим полям B и C. Поле B не обрабатывает ошибку, которая возникает, Aно C делает. Окончательное поле D не обращается и A поэтому оно не влияет на ошибку.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 
]

Результатом оценки приведенного выше выражения является:

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

Обработка ошибок в M должна быть выполнена близко к причине ошибок для устранения последствий инициализации ленивых полей и отложенных вычислений закрытия. В следующем примере показана неудачная попытка обработки ошибки с помощью try выражения:

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

В этом примере определение g было предназначено для обработки ошибки, возникаемой при вызове f. Однако ошибка вызывается инициализатором полей, который выполняется только при необходимости и таким образом после возврата записи из f и передается через try выражение.

Не реализована ошибка

Несмотря на разработку выражения, автор может отказаться от реализации для некоторых частей выражения, но может по-прежнему иметь возможность выполнять выражение. Один из способов обработки этого дела — вызвать ошибку для неимблированных частей. Например:

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

Символ многоточия (...) можно использовать в качестве ярлыка error.

not-implemented-expression:
      ...

Например, следующий пример эквивалентен предыдущему примеру:

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