Скажем, у меня есть набор параметров, которые я могу передать определенным процессам, например,
struct Options: OptionSet {
let rawValue: Int
static let floogled = Options(rawValue: 1 << 0)
static let jibjabbed = Options(rawValue: 1 << 1)
}
Они передаются некоторым функциям, например, foo(options: .floogled)
и bar(options: .jibjabbed)
.
Теперь, обычно, когда я вызываю эти функции, предполагается, что все опции должны быть включены.Таким образом, я мог бы определить функции со значениями по умолчанию, например
func foo(options: Options = [.floogled, .jibjabbed]) {
...
}
и так далее, а затем просто вызвать foo()
.Пока все хорошо.
Однако в исключительных случаях, когда я не хочу вызывать эти функции со всеми включенными параметрами, использование было бы намного более интуитивно понятным, если бы я мог указать, какие параметры не, чтобы включить, а не какие опции остаются включенными.Например, я бы предпочел позвонить foo(options: .notFloogled)
, чем foo(options: .jibjabbed)
.
Я могу придумать два способа сделать это.Первый способ - изменить определение набора параметров, чтобы его члены определялись отрицательно;другими словами
struct OptionsAlternative: OptionSet {
let rawValue: Int
static let notFloogled = Options(rawValue: 1 << 0)
static let notJibjabbed = Options(rawValue: 1 << 1)
}
Функции будут определены без параметров, отключенных по умолчанию;то есть
func foo(options: OptionsAlternative = []) {
...
}
И я мог бы назвать это как foo()
для поведения по умолчанию или foo(options: .notFloogled)
, когда мне нужно отключить определенные опции.Однако я не хочу этого делать, потому что это делает реализацию функций неинтуитивной.Я должен был бы реализовать части, которые принимают во внимание варианты в двойном отрицательном ключе;сравните, насколько это неуклюже:
if !options.contains(.notFloogled) {
// Floogling is enabled. Floogle the foo.
...
}
в отличие от
if options.contains(.floogled) {
// Floogling is enabled. Floogle the foo.
...
}
Второй способ - включить элементы для указания наличия опций, как в исходном решении, а также удобных членов, указывающих на отсутствие опций.Т.е.
extension Options {
/// Not floogled; only jibjabbed.
static let notFloogled: Options = [.jibjabbed]
/// Not jibjabbed; only floogled.
static let notJibjabbed: Options = [.floogled]
}
Однако, это не сработает, если я хочу отключить несколько опций (что, возможно, было основной причиной для использования набора опций в первую очередь).Например, если я сейчас вызываю foo(options: [.notFloogled, .notJibjabbed])
, я получаю опцию, установленную с включенными и floogling и jibjabbing вместо или .
Есть ли другой способделать то, что я пытаюсь достичь, сохраняя реализацию и использование максимально интуитивно понятным?