Swift 5.1, diline önemli bir yeni özellik getirmiştir. opak tipleri – ne tür bir nesne olduğunu bilmeden bir nesnenin yetenekleri hakkında bize söylenen türler. Bu gerçekleşti SE-0244Swift'deki genel işlevselliği geliştirmek için daha büyük bir yol haritasının parçası.

İlk bakışta opak tipler protokollere çok benziyor, ancak ilişkili kavramlarla çalışabildikleri için protokol kavramını daha da ileri götürüyorlar, aynı türün her seferinde dahili olarak kullanılmasını gerektiriyorlar ve uygulama ayrıntılarını gizlememize izin veriyorlar .

Örnek olarak, bir Asi üssünden farklı türden savaşçıları fırlatmak istiyorsak, şöyle bir kod yazabiliriz:

protokol savaşçısı {}
yapı XWing: Savaşçı {}

func launchFighter () -> Fighter {
    XWing ()
}

red5 olsun = launchFighter ()

Not: Swift 5,1 artık gerekli değil dönüş Tek ifade işlevlerinde anahtar kelime, yani XWing () aynıdır XWing () işlevini döndürBuradan daha fazlasını okuyabilirsiniz.

Bunu kim çağırırsa launchFighter () işlevi bir çeşit döndüreceğini bilir. savaşçı ama tam olarak ne olduğunu bilmiyor. Sonuç olarak ekleyebiliriz. yapı YWing: Avcı {} veya diğer tipler ve bunlardan herhangi birinin iade edilmesi.

Ancak bir sorun var: ya belirli bir dövüşçünün Kırmızı 5 olup olmadığını kontrol etmek istersek? Sen belki çözümün yapmak olduğunu düşünüyorum savaşçı uygun Equatable protokolü kullanabilmemiz için ==. Ancak, bunu yapar yapmaz Swift, özellikle korkunç bir hatayı giderir launchFighter function: “'Fighter' Protokolü, yalnızca Kendisi veya ilişkili tür gereksinimlerine sahip olduğundan genel bir kısıtlama olarak kullanılabilir.”

Bu hatanın “Ben” kısmı, bizi burada vuran şeydir. Equatable Protokolün aynı olup olmadığını görmek için iki örneği (“Ben”) karşılaştırması gerekir, ancak Swift, eşitlenebilir iki şeyin uzaktan aynı olduğunu garanti etmez – örneğin bir Fighter'ı bir tam sayı dizisi ile karşılaştırabiliriz. .

Opak tipleri bu sorunu çözerler çünkü Biz sadece bir protokolün kullanıldığını görün, dahili olarak Swift derleyicisi bu protokolün gerçekte ne çözdüğünü tam olarak bilir – bu bir XWing, bir dizi ip, ya da her neyse.

Opak bir tür geri göndermek için, anahtar kelimeyi kullanın. bazı protokol adınızdan önce:

func launchOpaqueFighter () -> bazı Fighter {
    XWing ()
}

Arayanın bakış açısına göre hala geri alır savaşçıbir olabilir XWing, bir YWing, veya uygun olan başka bir şey savaşçı protokol. Ama derleyici en perspektif tam olarak neyin geri döndüğünü bilir, böylece tüm kuralları doğru bir şekilde uyguladığımızdan emin olabilir.

Örneğin, dönen bir işlevi düşünün bazı Equatable bunun gibi:

func makeInt () -> bazı Eşitlenebilir {
    Int.random (in: 1 ... 10)
}

Bunu aradığımızda, bildiğimiz tek şey, bunun bir çeşit olduğu. Equatable Ancak, eğer iki kez ararsanız, bu iki görüşmenin sonuçlarını karşılaştırabiliriz çünkü Swift aynı temel tipte olacağını kesin olarak biliyor:

let int1 = makeInt ()
let int2 = makeInt ()
Yazdır (int1 == int2)

Aynı değil doğru olsaydı ikinci döndürülen işlev bazı Equatable, bunun gibi:

func makeString () -> bazı Eşitlenebilir {
    "Kırmızı"
}

Her ne kadar bizim bakış açımıza göre ikimiz de bize geri Equatable yazın ve biz kutu iki çağrının sonuçlarını karşılaştır makeString () veya iki arama makeInt (), Swift’in dönüş değerini karşılaştırmamıza izin vermiyor makeString () geri dönüş değerine makeInt () çünkü bir dizgeyi karşılaştırmayı biliyor ve bir tamsayı anlam ifade etmiyor.

Buradaki önemli bir şart, opak dönüş tipli fonksiyonların her zaman belirli bir tip döndürmesi gerektiğidir. Mesela kullanmaya çalıştık Bool.random () rastgele başlatmak XWing veya bir YWing o zaman Swift kodumuzu oluşturmayı reddeder çünkü derleyici neyin geri gönderileceğini artık söyleyemez.

“Her zaman aynı türü döndürmemiz gerekiyorsa, neden sadece işlevini yazmıyorsunuz?” Diye düşünebilirsiniz. func launchFighter () -> XWing? Bu bazen işe yarayabilir, ancak gibi yeni sorunlar yaratır:

  • Gerçekten dünyaya maruz bırakmak istemediğimiz türlerle son buluruz. Mesela eğer kullanırsak someArray.lazy.drop {…} geri gönderildik LazyDropWhileSequence – Swift standart kütüphanesinden özel ve oldukça özel bir tür. Tek umursadığımız şey, bu şeyin bir dizi olduğu; Swift’in iç dünyasının nasıl çalıştığını bilmemize gerek yok.

  • Daha sonra fikrimizi değiştirme yeteneğimizi kaybederiz. Yapımı launchFighter () sadece bir dönüş XWing Gelecekte farklı bir türe geçiş yapamayacağımız anlamına gelir ve Disney'in Star Wars oyuncak satışlarına ne kadar güvendiği göz önüne alındığında! Bir opak tip döndürerek bugün X-Wings'i geri getirebiliriz, daha sonra bir yıl içinde B-Wings'e geçebiliriz – yalnızca kodumuzun verilen herhangi bir yapısından birini geri getirebiliriz, ancak yine de fikrimizi değiştirme esnekliğine sahibiz.

Bazı açılardan, tüm bunlar “Kendine ya da ilişkili tip gereksinimleri” sorununu da çözen jeneriklere benzer gelebilir. Jenerikler şu şekilde kod yazmamıza izin verir:

protokol ImperialFighter {
    içinde()
}

yapı TIEFighter: ImperialFighter {}
yapı TIEAdvanced: ImperialFighter {}

func başlatmaImperialFighter() -> T {
    T ()
}

Bu, herhangi bir parametre ile başlatılamayan uyumlu tipler gerektiren yeni bir protokolü tanımlar, o protokole uyan iki yapıyı tanımlar, sonra kullanmak için genel bir işlev oluşturur. Ancak, buradaki fark şudur Arayanların arasında launchImperialFighter () Ne tür bir dövüşçü seçeceklerini seçenler, bunun gibi:

Fighter1 izin: TIEFighter = launchImperialFighter ()
fighter2 let: TIEAdvanced = launchImperialFighter ()

Eğer sen istemek Arayanlar veri türlerini seçebilmek için jenerikler iyi çalışır, ancak isterseniz fonksiyon geri dönüş tipine karar vermek için düşerler;

Dolayısıyla, opak sonuç türleri birkaç şey yapmamıza izin verir:

  • İşlevlerimiz, bu işlevlerin arayanı yerine ne tür verilerin döndürüleceğine karar verir.
  • Derleyici, içinde ne tür olduğunu tam olarak bildiği için, Öz veya ilişkili tür gereksinimleri hakkında endişelenmemize gerek yok.
  • İhtiyacımız olduğunda, gelecekte fikrimizi değiştiririz.
  • Özel iç tipleri dış dünyaya maruz bırakmıyoruz.

Protokoller ve opak tipler arasındaki farkı hiç unutursanız, şunu düşünün: returning savaşçı "her türlü savaşçı yazın ama ne olduğunu bilmiyoruz " bazı savaşçı "belirli bir tür" anlamına gelir savaşçı yazın ama hala ne olduğunu bilmiyoruz. ”İkinci durumda, fark, temel türün derleyicinin bildiği belirli bir şey olduğudur, oysa önceki durumda kelimenin tam anlamıyla protokole uygun bir şey olabilir – hatta Her seferinde yöntem farklı diyoruz.

Swift 5.1'den başka neler geliyor?

Swift 5.1, modül kararlılığı, üyelere göre başlatıcılara iyileştirmeler, tekli ifade işlevlerinden örtük getiriler ve daha fazlası gibi diğer yeni özellikleri tanıtıyor – makaleme bakın Swift 5.1'deki yenilikler tam arıza için.

Ve Swift 5.0'daki tüm yeni özellikleri kaçırdıysanız, yakalamak için asla geç değildir – makaleme bakın Swift 5.0'daki yenilikler daha fazla bilgi için.





Source link

Kategoriler: Genel

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir