Есть ли в Swift аналог оператора with из VBA и Delphi?
В VBA возможна такая запись обращения к свойствам и методам классов/структур:
With theCustomer
.Name = "Coho Vineyard"
.URL = "http://www.cohovineyard.com/"
.City = "Redmond"
End With
В Delphi/Object Pascal, в свою очередь, это делалось так:
with theCustomer do
Name := 'Coho Vineyard';
URL := 'http://www.cohovineyard.com/';
City := 'Redmond';
end;
В Swift ни оператор do { ... } не обеспечивает сокращения записи, ни в замыканиях я такого не нашёл. Я подозреваю, что что-то упустил.
Подскажите, плиз, чем можно заменить записи из приведённых двух примеров в этом языке. Какие есть варианты?
Ответы (2 шт):
К сожалению, в Swift нет каскадных записей. Можно самому написать некое подобие. Для классов все просто, особенно которые наследуются от NSObject, один раз прописал и можно пользоваться:
protocol Applyable {}
extension Applyable where Self: AnyObject {
@inlinable
@discardableResult
func apply(_ block: (Self) throws -> Void) rethrows -> Self {
try block(self)
return self
}
}
extension NSObject: Applyable {}
// Применение
let someView = UIView().apply {
$0.backgroundColor = .black
}
Так как структуры – value type, соответственно, с ними не получится так же. Чтобы их "завести" нужна промежуточная mutable переменная:
extension Applyable where Self: Any {
@inlinable
@discardableResult
func applied(_ block: (inout Self) throws -> Void) rethrows -> Self {
var mutableCopy = self
try block(&mutableCopy)
return mutableCopy
}
}
struct SomeTestStruct: Applyable {
var someTestValue: String?
}
// Применение
let someTestStruct = SomeTestStruct().applied {
$0.someTestValue = "Test"
}
Объединив два решения – перегрузку операторов и замыкания – из предлагаемых языком Swift и предлагаемых коллегами вариантов, удалось решить свою задачу.
Имеем для примера объявленную структуру и её расширение с искомой функцией (оператором):
struct Cell {
var point: CGPoint
}
extension Cell {
@inline(__always)
static func >> (left: inout Cell, right: (inout Cell) -> Void) {
right(&left)
}
}
В любом месте, где требуется сокращённая запись работает такой вызов:
data[x][y] >> {
$0.point.x = xPart + offsetX
$0.point.y = yPart + offsetY
}
В моём решении не требуется пропуск результата через атрибут @discardableResult.
Вторым вариантом решения будет создание нового протокола или расширение стандартного (скажем, Equatable, но я не уверен, что это «законно») с функцией-оператором. Пример создания своего протокола:
protocol Applyable {}
extension Applyable {
@inlinable
static func >> (left: inout Self, right: (inout Self) -> Void) {
right(&left)
}
}
extension NSObject: Applyable {
}
extension CGPoint: Applyable {
}
В таком решении равновозможны обе записи:
data[x][y] >> {
$0.point.x = xPart + offsetX
$0.point.y = yPart + offsetY
}
и
data[x][y].point >> {
$0.x = xPart + offsetX
$0.y = yPart + offsetY
}
Но «минусом» будет расширение каждого используемого типа, где требуется или направшивается сокращённая запись. И ещё надо подумать над оператором >>, что-то мне эти «стрелки» не нравятся. ))