2017-06-29 95 views
1

我想要做這樣的事情:是否可以將Int.init傳遞給Swift中的函數?

var x = ["10","20",30"] 
var y = x.map(Int.init) 

,但我得到這個錯誤

曖昧參考成員 '的init()'

我知道我可以只寫

var y = x.map { Int($0) } 

但我想知道是否有其他方式。

+0

您能詳細說明一下您的需求嗎? – Sajjon

+2

[在map()中使用init()]的可能重複(https://stackoverflow.com/questions/33906791/using-init-in-map)。 –

+0

@MartinR很好找。有趣的是編譯器不能消除初始化器的歧義。有時候你會很幸運,像'[false,true] .map(!)'這樣的東西可以工作。 – JAL

回答

5

問題是,不存在Int初始化程序,它只有 a String參數。

only exists

init?(_ text: String, radix: Int = default) 

雖然​​參數有一個默認值,這僅僅是在初始化器的調用點「填充」爲您編譯器。

當獲取對函數本身的引用時,默認參數值不會部分應用,也不會爲默認參數值的所有可能組合生成額外的重載。後者不僅會使代碼顯着膨脹,而且這兩個選項都會打破取決於在呼叫站點插入的默認參數值(例如#file & #line)。

爲了使其正常工作,函數值本身必須支持默認參數值,這會帶來相當多的複雜性。雖然它可能是未來版本的語言支持的東西。

一個簡單的解決方案,以得到你想要的行爲是隻寫上Int的擴展,它增加了一個init(_:)初始化器是再轉發到init(_:radix:)

extension Int { 
    /// Creates a new integer value from the given base-10 integer string, returning nil 
    /// if the string is in an invalid format. 
    init?(_ string: String) { 
     // we're saying (_:radix:) in order to disambiguate the call, the compiler 
     // will insert the default parameter value of radix: for us. 
     self.init(_:radix:)(string) 
    } 
} 

注意,在斯威夫特4,這可能是一個擴展FixedWidthInteger,它爲標準庫的整數類型提供了init(_:radix:)的實現。

現在,你可以說:

let x = ["10", "20", "30"] 
let y = x.map(Int.init) // [Optional(10), Optional(20), Optional(30)] 

Int.init現在指的是我們的擴展初始化器。

而且這也適用同樣出色flatMap(_:)

let y = x.flatMap(Int.init) // [10, 20, 30] 

這也將過濾掉從改造nil元素(即不轉換爲整數的字符串)。

+0

不錯!但是'y'仍然返回'[Int?]',可能不需要_optional_Ints。然後你可以在擴展中使用這個init結合'flatMap'來代替map' – Sajjon

+1

@Sajjon Yup,剛剛在添加的過程中,當你評論:)不清楚哪兩個OP想要,但想了想提到它並沒有什麼壞處。 – Hamish

+0

不錯! @ b-roy-dawson,你也可以使用這個解決方案,並把它擴展到[String]。像這樣:'擴展數組其中元素==字符串{整數:[Int] { return flatMap(Int.init) } }'with * usage:*'var y = x.integers' – Sajjon

1

問題歸結爲不能將具有默認參數的函數(如Int.init(_ text: String, radix: Int = default))分配到只有在「默認」參數「不存在」時才能「適合」的地方。

當你自己關閉,{ Int($0) },你告訴編譯器你想要默認值radix適用。這不幸的是,這並不是隱含的。

相關問題