Atamadan sonra genel "T" parametresi çıkarılamadı
// Xcode 11.6 / Swift 5
import Foundation
func f<T>(_: (T) -> Void) { }
@discardableResult
func g(_: Int) -> Int { 0 }
f { g($0) } // compiles fine f { let _ = g($0) } // Generic parameter 'T' could not be inferred
Yukarıdaki kodda, genel işlev f
bağımsız değişken olarak bir tür bağımsız değişken alan bir işlev bekler T
.
İşlev g
, türde bir bağımsız değişken alır Int
.
Ben yazarken f { g($0) }
, kod derleme yapar. Ben inanıyorum derleyici sonucuna çünkü (yanılıyorsam düzelt lütfen) bu derler T
bir olduğunu Int
dayanan g
'ın argümanı türü.
Ancak, g
örneğin let _ = g($0)
satırında dönüş değeri olan bir şey yapmaya çalıştığımda , derleyici artık T
.
Bana öyle geliyor ki dönüş türünün g
derleyicinin T
türünü nasıl belirlediğiyle ilgisi yok , ama açıkça öyle.
Birisi bunun neden olduğuna biraz ışık tutabilir mi ve düzeltmek için (eğer bir şey varsa) ne yapılabilir?
Yanıtlar
Bu bir derleyici hatası olabilir veya olmayabilir.
SR-1570'de söylendiği gibi Swift'in bazı kapanış türlerini, yani çok ifadeli olanları çıkarmaya çalışmadığı biliniyor :
Bu doğru davranıştır: Swift, çoklu ifade kapanışlarının gövdelerinden parametre veya döndürme türleri çıkarmaz.
Bununla birlikte, kapanışınız yalnızca bir ifadeden oluşur, spesifik olması gereken bir beyan. Garip de olsa, kapanış tek bir bildirim içeriyorsa Swift'in türleri anlamaya çalışmaması için tasarlamış olmaları mümkündür . Örneğin, bu da derlenmez
f { let x: Int = $0 } // nothing to do with "g"! The issue seems to be with declarations
Bu tasarım gereği olsaydı, arkasındaki mantık, kapanıştaki tek bir bildirimin zaten pek bir anlam ifade etmeyeceği olabilir. Bildirilen ne olursa olsun kullanılmayacaktır.
Ama yine, bu sadece bir spekülasyon ve bu da bir hata olabilir.
Düzeltmek için, basitçe bir beyan değil yapın:
f { _ = g($0) } // this, without the "let", is IMO the idiomatic way to ignore the function result
Veya
f { g($0) } // g has @discardableResult anyway, so you don't even need the wildcard
İşlev f
, bir işlevi parametre olarak alır ve bu da daha sonra türden bir parametre alır T
ve hiçbir şey ( Void
) döndürmez . Tiplerin otomatik olarak çıkarılması için bir kapanış tek (ve bazen basit) ifadeden oluşmalıdır. Karmaşık olan herhangi bir şey, derleyicinin çıkarım yapmasını zorlaştırır (bu, derleyicinin bakış açısından anlamlıdır). Görünüşe göre, let _ = g($0)
derleyici söz konusu olduğunda karmaşık bir ifadedir. Daha fazla bilgi için, bu posta listesi tartışmasına bakın
@discardableResult size 2 tür işleve sahip olma yeteneği veriyor gibi görünüyor:
g (_: Int) -> Int ve g (_: Int) -> Void (fonksiyonun bir sonucunu kullanmak istemediğiniz zamandır)
bence
f { g($0) }
- burada f aynı Tipi çünkü bir tür çıkarabiliriz
(_: (T) -> Void) and (_: (Int) -> Void)
f { let _ = g($0) }
- bu durumda g işlevinin türü f işlevinden farklıdır
(_: (T) -> Void) and (_: (Int) -> Int)
Eğer "let" i kaldırırsanız, tekrar derlenecektir:
f { _ = g($0) }
Bence f { let _ = g($0) }
- yalnızca Int değeri döndür f { _ = g($0) }
- dönüş işlevi (_: (Int) -> Int)
Belki burada bir anahtardır