То, что вы, похоже, делаете, это карри . Вы удаляете много дублированного кода, извлекая функцию curry
:
func curry<A,B,C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
return { a in { b in f(a, b) } }
}
// ...
var op: (Double) -> (Double) -> Double {
switch self {
case .plus: // please follow Swift naming conventions, enum cases start with a lowercase
return curry(+)
case .minus:
return curry(-)
case .multiply:
return curry(*)
case .unsafeDivide:
return curry(/)
}
}
Это уже выглядит намного лучше. Похоже, вам не нравятся операторы switch, поэтому вот как вы это сделаете со словарем:
var op: (Double) -> (Double) -> Double {
let dict: [Operate: (Double, Double) -> Double] =
[.plus: (+), .minus: (-), .multiply: (*), .unsafeDivide: (/)]
return curry(dict[self]!)
}
Фактически, вы можете использовать новую функцию callAsFunction
в Swift 5.2 опустить даже слово op
на стороне вызывающего абонента:
func callAsFunction(_ a: Double) -> (Double) -> Double {
op(a)
}
Это позволяет вам:
Operator.multiply(2)(3)
Использование связанных значений равно по-другому:
enum Operate {
case plus(Double)
case minus(Double)
case multiply(Double)
case unsafeDivide(Double)
func callAsFunction(_ b: Double) -> Double {
switch self {
case .plus(let a):
return a + b
case .minus(let a):
return a - b
case .multiply(let a):
return a * b
case .unsafeDivide(let a):
return a / b
}
}
}
Но мне лично это не нравится, поскольку наличие связанных значений означает, что вы не можете просто использовать ==
для сравнения значений перечисления, среди других ограничений.
Запрет деления на 0 во время компиляции невозможен, поскольку передаваемые вами значения могут не быть константами времени компиляции. Если вы просто хотите проверить постоянные времени компиляции, вам может понадобиться статический анализатор кода c, такой как SwiftLint. Во время выполнения деление Double
0 в любом случае четко определено стандартом IEEE. Это не будет sh или что-нибудь еще.