Swift имеет несколько функций высокого порядка , таких как map
, которые поддерживают парадигмы функционального программирования (например, объединение функций в цепочку).
Например:
users // e.g. [User]
.map(Person(from:)) // e.g. protocol Person { init(from: User) }
.map { $0.name } // e.g. protocol Person { var name: String { get } }
.map(Person.normalizedName(fromName:)) // e.g. protocol Person { static func normalizedName(fromName: String) -> String }
.map(User(username:) // e.g. protocol User { init(username: String) }
Это работает, потому что оно начиналось с массива [User]
, и каждый элемент был мутирован по пути.
Теперь представьте мы пытаемся манипулировать CGPoint
вместо массива с помощью следующего традиционного кода:
let point: CGPoint = input
let flippedPoint = CGPoint.flipHorizontally(point)
let halvedPoint = CGPoint(x: flippedPoint.x / 2.0, y: flippedPoint.y)
let rect = CGRect(at: halvedPoint)
Этот код невыгоден, потому что: (A) он требует, чтобы на каждом шаге создавалось имя промежуточной переменной функции, и (B) вы можете легко сделать ошибку logi c, которая прекрасно компилируется (например, CGPoint(x: point.x / 2.0, y: flippedPoint.y)
).
Вы можете попытаться решить (A), связав все это в одну строку :
CGRect(at: CGPoint(x: CGPoint.flipHorizontally(point).x / 2.0, y: CGPoint.flipHorizontally(point).y))
Однако, это грязно и еще более подвержено ошибкам (например, обратите внимание на два вызова, которые нужно сделать на CGPoint.flipHorizontally(point)
.
Теперь представьте, что это будет выглядеть, как если бы вы могли позвонить map
на CGPoint
:
point // e.g. CGPoint
.map(CGPoint.flipHorizontally(_:)) // e.g. extension CGPoint { static func flipHorizontally(_ point: CGPoint) -> CGPoint }
.map { CGPoint(x: $0.x / 2.0, y: $0.y) }
.map(CGRect.init(at:)) // e.g. extension CGRect { init(at: CGPoint) }
Этот код намного чище, чем любой из двух вариантов.
Is Есть ли способ вызвать map
(или другие высокоуровневые функции) для не-типа коллекции?
Я понимаю, что один из обходных путей - это обернуть / развернуть массив, но я надеюсь, что есть более неуклюжий способ:
[point]
.map(CGPoint.flipHorizontally(_:))
.map { CGPoint(x: $0.x / 2.0, y: $0.y) }
.map(CGRect.init(at:))
.first!
Второй обходной путь - обернуть в Optional
, но это допускает только map
и flatMap
и также неуклюже:
Optional(point)
.map(CGPoint.flipHorizontally(_:))
.map { CGPoint(x: $0.x / 2.0, y: $0.y) }
.map(CGRect.init(at:))!