İki Swift struct değerini birleştirmek için her alanın kaynağını seçen ve yeni bir değer döndüren bir işlev yazın. Bu macOS örneği, değiştirme, koruma, isteğe bağlı değeri temizleme ve geçersiz girdi için açık kurallarla iki sentetik çizim paneli stilini birleştirir.

Birleştirme işlevini yazmadan önce hangi değerin kazanacağını belirleyin

Okuyucunun görevi, Mac'te mevcut iki değerden tek bir çizim paneli stili hesaplamaktır. Girdileri base ve incoming olarak adlandırın: bu adlar rollerini açıklar, hangi değerin kazanacağını ise alan bazında belirlenen bir sözleşme tanımlar. Hesaplama yalnızca bellekteki sentetik değerleri kullanır.

Swift, yapıları değer türleri olarak belgeler ve başlatıcılar aracılığıyla örnekler oluşturmayı destekler. Apple'ın belgelenmiş merge(_:uniquingKeysWith:) API'si Dictionary'ye aittir ve yinelenen anahtarları bir kapanış kullanarak çözümler. Bu özel struct için, uygulaması amaçlanan alan kurallarını ifade eden bir birleştirme işlevi tanımlayın. Yapılar ve Sınıflar, Dictionary merge(_:uniquingKeysWith:).

Aşağıdaki örnek sözleşmeyi kullanın. Bunlar, Swift'in otomatik olarak sağladığı davranışlar değil, bu örnek için seçilmiş tasarım kararlarıdır.

Alan Kural Örnek sonuç
title Gelen metni al, çevresindeki boşlukları ve satır sonlarını kırp, ardından sonuç boşsa reddet " Tile Study \n" değeri \"Tile Study\" olur
spacing Temel değeri koru; negatif olmamasını zorunlu kıl Temel 12, gelen 30 yerine kullanılır
showsGrid Gelen Boolean değerini olduğu gibi al Gelen false, temel true değerinin yerini alır
caption Gelen isteğe bağlı değeri olduğu gibi al Gelen nil, temel başlığı temizler

Bu tablo, kolayca birbirine karıştırılabilen üç işlemi ayırt eder: bir kaynak seçmek, seçilen değeri normalleştirmek ve sonucu doğrulamak. Gelen aralık değeri bilerek kullanılmaz. Değeri temel aralıktan farklı olsa bile çıktıyı değiştiremez.

Foundation'daki trimmingCharacters(in:), her iki uçtan eşleşen karakterleri kaldırarak yeni bir dize döndürür. Apple, çevredeki boşluklar için .whitespacesAndNewlines kullanımını belgeler; tamamen bu karakterlerden oluşan bir dize boş hâle gelir. Bu boş sonucu reddetmek ise bizim ek kuralımızdır. Foundation trimmingCharacters(in:).

Mac'inizde eksiksiz bir yerel örneği çalıştırın

Bu örnek için Swift 6 araç zincirini kullanın. Swift.org, Swiftly aracılığıyla macOS kurulum yönergeleri sunar ve Apple platformlarında geliştirme için Xcode'u bir seçenek olarak belirtir. Terminal'i açın ve komutun kullanılabilir olduğunu doğrulamak için swift --version komutunu çalıştırın. Komut yoksa devam etmeden önce kurulum yönergelerini izleyin. Swift'i macOS'e yükleme, Başlarken.

Aşağıdaki eksiksiz programı çalışma klasörünüzde MergeStyles.swift adıyla kaydedin. Foundation'ı içe aktarır, iki girdi değerini tanımlar, birleştirme işlemini yapar, beklenen sonucu denetler ve iki ret durumunu sınar. Hesaplama ağ isteği yapmaz ve uygulama verisi saklamaz.

import Foundation

struct PanelStyle: Equatable, Sendable {
    let title: String
    let spacing: Int
    let showsGrid: Bool
    let caption: String?
}

enum StyleMergeError: Error {
    case emptyTitle
    case negativeSpacing
}

func mergeStyles(
    base: PanelStyle,
    incoming: PanelStyle
) throws -> PanelStyle {
    let title = incoming.title.trimmingCharacters(
        in: .whitespacesAndNewlines
    )
    guard !title.isEmpty else {
        throw StyleMergeError.emptyTitle
    }
    guard base.spacing >= 0 else {
        throw StyleMergeError.negativeSpacing
    }

    return PanelStyle(
        title: title,
        spacing: base.spacing,
        showsGrid: incoming.showsGrid,
        caption: incoming.caption
    )
}

let base = PanelStyle(
    title: "Shape Study",
    spacing: 12,
    showsGrid: true,
    caption: "Blue squares"
)
let incoming = PanelStyle(
    title: "  Tile Study \n",
    spacing: 30,
    showsGrid: false,
    caption: nil
)

let expected = PanelStyle(
    title: "Tile Study",
    spacing: 12,
    showsGrid: false,
    caption: nil
)

let result = try mergeStyles(base: base, incoming: incoming)
precondition(result == expected)
precondition(base.title == "Shape Study")
precondition(base.caption == "Blue squares")
precondition(incoming.title == "  Tile Study \n")

print(result.title)
print("spacing: \(result.spacing)")
print("grid: \(result.showsGrid)")
print("caption cleared: \(result.caption == nil)")

let blankTitle = PanelStyle(
    title: " \n\t",
    spacing: 30,
    showsGrid: false,
    caption: nil
)
do {
    _ = try mergeStyles(base: base, incoming: blankTitle)
    preconditionFailure("Expected emptyTitle")
} catch StyleMergeError.emptyTitle {
    print("Rejected blank title")
}

let negativeBase = PanelStyle(
    title: "Shape Study",
    spacing: -1,
    showsGrid: true,
    caption: "Blue squares"
)
do {
    _ = try mergeStyles(base: negativeBase, incoming: incoming)
    preconditionFailure("Expected negativeSpacing")
} catch StyleMergeError.negativeSpacing {
    print("Rejected negative spacing")
}

Dosyanın bulunduğu klasörden şu komutu çalıştırın:

swift MergeStyles.swift

Beklenen çıktı aşağıda gösterilmiştir. Araştırma ortamında Swift kullanılamadığından bu program incelendi, ancak orada çalıştırılmadı.

Tile Study
spacing: 12
grid: false
caption cleared: true
Rejected blank title
Rejected negative spacing

Başlatıcı, kararların alındığı temel noktadır: her bağımsız değişken, seçilen bir girdi alanını veya adı verilmiş bir ara değeri belirtir. Girdilerin hiçbiri değiştirilmez. Swift'in değer semantiği bu yaklaşımı destekler; buradaki alanların kendileri de değer türleridir. Daha sonra sınıf türünde bir alan eklerseniz, kapsayıcı struct'ı kopyalamak başvurulan sınıf örneğini ayrıca kopyalamaz. Yapılar ve Sınıflar.

Doğrulama, örnek oluşturulmadan önce yapılır. Boş gelen başlık temel başlığın sessizce geri yüklenmesine yol açmak yerine hata fırlatır; negatif temel aralık da sessizce sıfıra sabitlenmek yerine hata fırlatır. Her iki koşul da sağlanmazsa, ilk olarak çalışan guard bu olduğundan emptyTitle bildirilir. Çağıranlar sonucu kullanmadan önce hatayı ele almalıdır.

İsteğe bağlı bir değerin temizleme mi yoksa koruma mı anlamına geleceğine karar verin

Ana örnek, incoming.caption değerini istenen başlığın tamamı olarak ele alır. Bu nedenle nil, “sonuçta başlık yok” anlamına gelir. Temsil yalnızca bir isteğe bağlı değer olsa da bu, temizleme işlemini sözleşmede açık hâle getirir.

Farklı bir gereksinimde gelen nil, “temel başlığı koru” anlamına gelebilir. Bu politikada, değiştirme başlatıcısının bağımsız değişkeni caption: incoming.caption ?? base.caption olur. Swift'in nil birleştirme operatörü, sol işlenen değer içeriyorsa onu, içermiyorsa sağ işleneni seçer. Bu, etiketli bir değiştirme parçasıdır; ikinci bir eksiksiz program değildir. Nil birleştirme operatörü.

Bu geri dönüş politikası, aynı gelen nil değerini temizleme isteği olarak da kullanamaz. İfadeyi benimsemeden önce anlamını seçin. Boş dize ayrı bir değerdir: her iki politikada da açıkça normalleştirme eklemediğiniz sürece gelen \"\" başlığı boş başlık olarak kalır.

Gelecekteki bir düzenleme işlemi üç eylemin tümünü—koru, değiştir ve temizle—gerektiriyorsa eylemi ayrıca temsil edin. Aşağıdaki bağımsız ve eksiksiz program, özel bir enum kullanarak yalnızca başlığa yönelik bir işlemi gösterir:

enum CaptionChange {
    case keep
    case set(String?)
}

func applying(
    _ change: CaptionChange,
    to caption: String?
) -> String? {
    switch change {
    case .keep:
        return caption
    case .set(let replacement):
        return replacement
    }
}

let original: String? = "Blue squares"
precondition(applying(.keep, to: original) == original)
precondition(applying(.set("Green circles"), to: original)
    == "Green circles")
precondition(applying(.set(nil), to: original) == nil)
print("Caption actions checked")

Bu enum, sözleşmenin örnek amaçlı bir genişletmesidir. Her iki girdi de eksiksiz stillerse özgün iki değerli işlevi kullanın; girdi düzenlemeleri tarif ediyorsa bir eylem türü ekleyin.

Önceliği kasıtlı olarak farklı değerlerle denetleyin

İyi bir birleştirme denetiminde çakışan alanların değerleri farklı olur. Her iki girdi de 12 aralığını kullanıyor ve ızgarayı etkinleştiriyorsa yanlış kaynak seçimi fark edilmeden geçebilir. Örnek bunun yerine 12 ile 30 ve true ile false değerlerini kullanır; böylece beklenen sonuç bu seçimleri ortaya çıkarır.

İşlevi uyarlamadan önce şu sınır durumlarını amaçlanan sözleşmeye göre denetleyin:

  • Gelen false, false olarak kalmalıdır; değiştirmeyi ifade etmek için Boolean OR kullanmayın.
  • Ana politikaya göre gelen nil başlığı temizlemelidir.
  • Başlığın çevresindeki boşluklar kaldırılmalı, içindeki boşluklar korunmalıdır.
  • Yalnızca boşluklardan oluşan gelen bir başlık, temel değere geri dönmeden hata fırlatmalıdır.
  • Temel aralık 0 başarılı olmalı; negatif temel aralık hata fırlatmalıdır.
  • Bağımsız değişkenlerin sırasını değiştirmek, kuralları yeni atanan rollere uygulamalıdır.

Son nokta önemlidir; çünkü bu birleştirme işleminde sıra sonucu değiştirir. Örnek girdilerin sırası tersine çevrildiğinde \"Shape Study\", 30 aralığı, true ızgara değeri ve \"Blue squares\" başlığı seçilir. Bu, belirtilen kuralların sonucudur. Rollerin görünür kalması için çağrı yerlerinde her iki bağımsız değişkene de ad verin.

Bir alan eklerken tabloyu, başlatıcıyı ve çakışan değerler kullanan bir denetimi genişletin. Gelecekte iç içe bir stil birden fazla bağımsız ayar içerirse iç içe değerin tamamının mı değiştirileceğine, yoksa alanlarının her birinin kendi önceliği mi olacağına karar verin. Mevcut uygulama yalnızca gösterilen dört alanı tanımlar.

Eşzamanlılığı birleştirme politikasından ayrı tutun

Bu hesaplama eşzamanlıdır: bağımsız değişkenlerini okur, seçilen değerleri doğrular ve bir sonuç döndürür ya da hata fırlatır. Önceliği belirlemek için görev veya aktör gerekmez. Swift, eşzamansız işlevleri askıya alınabilen işlevler olarak belgeler; eşzamansız yürütme eklemek hangi alanın kazanacağını belirlemez. Eşzamanlılık.

Örnek, değerlerinin eşzamanlılık sınırlarını aşabileceğini ifade etmek için PanelStyle'ı Sendable olarak bildirir. Apple, gönderilebilir bir struct'ın gönderilebilir üyeler içermesini şart koşar. Bu uygunluk değerlerin aktarılmasıyla ilgilidir; alan seçimi kuralları hâlâ tamamen mergeStyles tarafından belirlenir. Sendable.

Bu yerel çizim paneli görevi için sözleşmeyi işlevin yanında tutun ve belirgin biçimde farklı örnek girdiler kullanın. Sonuç, her alan için ayrı ayrı açıklanabilmelidir: normalleştirilmiş gelen başlık, korunan temel aralık, gelen ızgara ayarı ve önceki değeri açıkça temizleyebilen gelen başlık.

Kaynaklar