Ограничивающий метод или класс для приема только дополнительных опций - PullRequest
0 голосов
/ 09 июля 2020

Мне нужно ограничить API, чтобы пользователи могли вызывать его только с явно необязательными типами. Как я могу это сделать?

class Foo<T> {

    let value: T?

    init(_ value: T?) {
        self.value = value
    }
}

let optionalValue: Bool? = true
Foo(optionalValue) // Should work

let nonOptionalValue: Bool = true
Foo(nonOptionalValue) // Should fail, ideally at compile time

Foo(true) // Should work or acceptable to replace it with 
Foo(.some(true))

Ответы [ 2 ]

0 голосов
/ 09 июля 2020

Одним из вариантов может быть объявление init со свойством inout.

init(_ value: inout T?) {
    self.value = value
}

Теперь строка ниже выдает ошибку компилятора «Аргумент Inout может быть установлен на значение с типом, отличным от 'Bool'; используйте значение объявлен как тип "Bool?" вместо «

Foo(&nonOptionalValue) // Should fail, ideally at compile time

Ограничения:

  1. Пользователь класса Foo может не захотеть передавать по ссылке.
  2. Пользователь не сможет писать Foo (true )

Но это можно обойти, создав локальную переменную перед вызовом init.

0 голосов
/ 09 июля 2020

Проблема в том, что если вы передаете необязательное, где ожидается необязательное, то необязательное не отклоняется; вместо этого он неявно заключен в Optional. Вот почему эта строка кода является допустимой:

let optionalValue: Bool? = true

И по той же причине эта строка кода допустима:

let nonOptionalValue: Bool = true
Foo(nonOptionalValue) // even though Foo's parameter is typed as Optional

Вы не можете отключить эту функцию. Это запечено в языке. И действительно, как показывает первый пример, вы сами стали на это полагаться! Таким образом, именно по этой причине вы никогда не сможете предотвратить передачу здесь не-Optional. Это цена, которую мы платим за удобство неявной опциональной упаковки.

...