2014-09-29 89 views
8

我定義了兩個泛型函數如何在Swift中調用不明確的泛型函數?

func job<T: Comparable>(x: T) { 
    println("1") 
} 

func job<T: Hashable>(x: T) { 
    println("2") 
} 

,當我嘗試調用其中之一,例如用:

當然
let myInt: Int = 1 // Explicit Int just for clarity of the example 
job(myInt) 

斯威夫特抱怨並拋出一個錯誤
曖昧使用'工作'
這是可以理解的,因爲不清楚我是否想用可比較的 one或HashableInt符合他們兩個)

有沒有辦法我可以提示編譯器哪一個我想用?

+1

'job(myInt as Hashable)'工作嗎? – 2014-09-29 20:36:42

+1

Nope :(我得到2個錯誤: 'Protocol'Hashable'只能用作通用約束,因爲它具有Self或Assosiated類型的要求' AND'Type'Hashable'不符合協議'Comparable''一個聽起來很奇怪:)) – 2014-09-29 20:41:05

+0

FYI爲最新的快速注意這兩個很好的答案... http://stackoverflow.com/a/39836054/294884 ... http://stackoverflow.com/a/39835658/294884 – Fattie 2016-10-18 20:07:01

回答

10

這是不明確的,因爲IntHashableComparable,並且這兩個協議都不在同一個層次結構中。 (您可以查看Intprotocol hierarchy on Swifter

func f<T: Hashable>(t: T) { 
    println("Hashable: \(t)") 
} 
func f<T: Comparable>(t: T) { 
    println("Comparable: \(t)") 
} 

let number = 5 
f(number) 
// error: ambiguous use of 'f' 

你不能明確告訴的,因爲每個協議的相關類型要求它調用哪個函數,但你可以定義是第三個功能:

func f<T: Comparable where T: Hashable>(t: T) { 
    println("Both Hashable & Comparable: \(t)") 
} 
f(number) 
// Both Hashable & Comparable: 5 

這是怎麼Swift implements..<操作,否則將是曖昧實現既ComparableForwardIndexType類型。


爲了進一步擴大一點,這裏就來看看我的意思是「你不能明確告訴它調用哪個函數,因爲每個協議的相關類型的需求。」協議可以被用作類型,如在夫特書chapter on Protocols描述:

protocol RandomNumberGenerator { 
    func random() -> Double 
} 

class Dice { 
    let generator: RandomNumberGenerator 
    // ... 
} 

在這個例子中,發生器屬性可以是任何類型的符合RandomNumberGenerator - 類似id<ProtocolName>是如何在Objective-C使用。但是,協議可以使用只有作爲類型,但它們的聲明中不包含關聯類型或參考Self。這不幸地排除了Swift中幾乎所有的內置類型,包括HashableComparable。從Equatable

Hashable繼承,限定==操作者當其引用Self

func ==(lhs: Self, rhs: Self) -> Bool 

Comparable不與其運行相同:

func <=(lhs: Self, rhs: Self) -> Bool 
// similar definitions for <, >, and >= 

這些協議可以被用作通用約束,並且在聲明變量時不用作類型。 (據我所知,這是無證的,但通過錯誤消息可以發現。)

兩個協議的這個限制是PrintableBooleanType,所以我們可以看看他們是如何工作的。 Bool是唯一符合BooleanType的內置類型,它也是Printable,所以這將是我們的測試類型。這是我們的通用功能p()和可變t - 值得注意的是,和以前一樣,我們不能只調用函數與t

func p<T: Printable>(t: T) { 
    println("Printable: \(t)") 
} 
func p<T: BooleanType>(t: T) { 
    println("BooleanType: \(t)") 
} 

let t: Bool = true 
p(t) 
// error: Ambiguous use of 'p' 

相反,我們需要轉換(向上轉型?)t特定協議使用as關鍵字,並調用特定的通用功能的方法:所以只要我們有一個合格的協議

p(t as Printable) 
// Printable: true 

p(t as BooleanType) 
// BooleanType: true 

,我們可以選擇調用的泛型方法的變型。

+1

爲了澄清,「Comparable」和「Hashable」方法只是爲了證明問題。我不期望需要它們,但我想了解未來我可能會受到多少限制。現在,我不確定你的意思是「你不能明確地告訴它要調用哪個函數,**因爲每個協議的相關類型要求**」。能夠向編譯器提供有關使用哪種方法的提示時,是否存在一些基本問題?你認爲我們未來可以期待這樣的功能嗎? – 2014-09-29 21:19:53

+0

是不是告訴編譯器使用哪種函數來反對泛型編程的設計(一般來說,不只是在Swift中)?無論如何,如果有一個功能你希望在未來看到(或者至少被告知不要指望),那麼最好[提交bug](http://bugreport.apple.com)。 – rickster 2014-09-29 23:22:31

+0

@BartekChlebek:在這一點上增加了一點(好的,很多)的解釋。斯威夫特當然在不斷變化,但我不一定看到它需要改變。這種衝突似乎比較罕見,不是嗎? – 2014-09-30 01:54:44