Atamadan sonra genel "T" parametresi çıkarılamadı

Aug 18 2020
// 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 fbağı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 Tbir olduğunu Intdayanan 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 gderleyicinin Ttü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

2 Sweeper Aug 18 2020 at 11:45

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
2 Malik Aug 18 2020 at 11:44

İşlev f, bir işlevi parametre olarak alır ve bu da daha sonra türden bir parametre alır Tve 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

AlexanderNikolaychuk Aug 18 2020 at 11:44

@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