swift - titletextattributes - uinavigationbar title font




Что такое тип возврата никогда? (3)

Что делает func с типом возврата Never ?

Например:

func addNums() -> Never {

    //my code

}

Какая будет разница, если я оставлю тип возврата как Void как это?

func addNums() -> Void {

    //my code

}

Предположим, я хочу обработать fatalError (как сказано в dpassage ); ниже код будет достаточно:

print("its an error")
return

Документация Apple гласит:

Возвращаемый тип функций, которые не возвращаются нормально, то есть тип без значений.

Источник: Developer

Это был не повторяющийся вопрос о том, когда и как использовать атрибут @noreturn в Swift? , как я хотел бы получить более подробный ответ, который нуждается в таких деталях, как:

  1. Практические примеры различий между типами возвращаемых Never и Void

  2. Условие, по которому мы должны принять эти типы возврата.

  3. Также есть вероятность, что тип возвращаемого значения может быть nil; Мне нужно сравнение этой функции тоже

Ответ должен быть сосредоточен на различиях.


Чтобы лучше понять Never и Void и то, как Never полезен в большем количестве контекстов, чем был старый @noreturn , давайте сначала посмотрим, как на самом деле определяются эти два типа:

Never не определяется here как:

public enum Never {}

Поскольку нет способа создания экземпляра значения пустого перечисления, система типов гарантирует, что ни один экземпляр Never может существовать. Это означает, что функции, которые определяют тип возвращаемого значения как Never могут быть возвращены системой типов при любых обстоятельствах.

Компилятор учитывает это при анализе потока управления. Например, обе эти функции компилируются без ошибок, тогда как они потерпят неудачу, если функция, которая возвращает Void была заменена на fatalError :

func foo(fail: Bool) -> String {
    if fail {
        fatalError()
    } else {
        return "foo"
    }
    // notice there is no return statement here
}

func bar(fail: Bool) -> Void {
    let s: String
    if fail {
        fatalError()
        // the compiler doesn't complain s is not initialized here
    } else {
        s = "bar"
    }
    print(s)
}

Void определяется here как:

public typealias Void = ()

Нет двух разных экземпляров пустого кортежа. Таким образом, возвращаемое значение функций, возвращающих Void содержит никакой информации.

Вы можете написать return () или return Void() . Вы также можете использовать возвращаемое значение, например:

func empty() -> Void {}
let v = empty()
print(type(of: v)) // prints "()"

хотя компилятор предупредит «константа v», имеющая тип «Void», что может быть неожиданным ».

Определение как Never и Void с точки зрения системы типов, а не как специальных возможностей языка, позволяет нам делать довольно умные вещи с обобщениями. Давайте рассмотрим пример типа Result , общего как для типа успеха, так и для типа ошибки.

enum Result<R, E> {
    case success(R)
    case failure(E)
}

Возможная специализация этого будет Result<Void, MyError> . Это будет означать, что у вас есть результат, который при успехе не содержит никакой информации, кроме того, что он достиг успеха.

Другой возможностью может быть Result<String, Never> . Этот результат гарантируется компилятором, чтобы никогда не быть случаем отказа.

Дополнительные функции взаимодействуют с Never и Void аналогичным образом. Never? может быть только ноль и Void? только содержит информацию, является ли она нулевой или нет, ничего более (это в основном более сложный Bool). Оба из них не очень полезны сами по себе, но могут появиться, когда Never или Void используются где-то в качестве общих параметров.

На практике вы редко будете писать функции, возвращающие Never . Я лично использовал это, чтобы обернуть fatalError чтобы создать функцию, которую я использую, чтобы отметить функции, которые еще не реализованы:

func unimplemented(f: String = #function) -> Never {
    fatalError("\(f) is not implemented yet")
}

Другим примером функции, возвращающей Never является dispatchMain() , который можно использовать в служебных программах командной строки для запуска DispatchQueue.main . Поскольку эта очередь ожидает новых блоков, dispatchMain() никогда не возвращается.


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

Это отличается от функции, которая просто не возвращает значение, как в вашем втором фрагменте. Вы также можете написать это как func addNums() -> Void .


пустота

Void сам по себе является типом возврата, который является кортежем с нулевыми элементами. Вы можете использовать Void и () взаимозаменяемо.

Посмотрите на эти примеры,

  1. func yourFunc() {} Это функция без возвращаемого типа, которая в основном возвращает кортеж с нулевыми элементами, который можно записать как ()

  2. func yourFunc() -> Void {} Функция, которая явно информирует компилятор о типе возвращаемого значения void

  3. func yourFunc() -> () {} Этот тип возврата () отображается так же, как и тип void. () указывает на кортеж с нулевыми элементами

Никогда

Никогда не возвращаемый тип информирует компилятор о том, что нет необходимости возвращать пустой кортеж (). Кроме того, функция с типом «никогда не возвращать» используется для точки выхода текущего выполнения, такой как сбой, фатальная ошибка, прерывание или выход.

Для детального понимания никогда , давайте посмотрим на пример abort ():

1.

 func yourFunc() {
    abort()
    print("Will not reach at this point") //Warning for this line
} 

2.

 func yourFunc() -> Int {
    if true {
        abort()
    } else {
        return 1
    }
}

Из приведенных выше фрагментов кода мы можем видеть, когда мы вызываем abort () (который не возвращает значение) в качестве последнего оператора в функции, которая ожидает, что значение будет возвращено (в нашем случае Int). Компилятор не генерирует предупреждение.

прервать ()

public func abort() -> Never

Аналогично для выхода ():

public func exit(_: Int32) -> Never

Документация Apple гласит: « Никогда не используйте тип возвращаемого значения при объявлении замыкания, функции или метода, который безоговорочно генерирует ошибку, прерывает или иным образом не завершает работу ».

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

func catastrophicErrorDisplay(error: String) -> Never {
    DisplaySomeCustomLogFacility(error)
}

Короче говоря, « Никогда не используется для внезапного и полного отказа, из которого восстановление невозможно ».





types