Swift:只在返回types中有所不同的方法重载

我不断看到Swift类,其中定义了两种方法,只是返回types不同。 我不习惯在允许这样的语言(Java,C#等)中工作,所以我去寻找描述在Swift中如何工作的文档。 我什么都找不到。 我本来期待Swift书中的整个章节。 这在哪里logging?

这是我正在谈论的一个例子(我正在使用Swift 2,FWIW):

class MyClass { subscript(key: Int) -> Int { return 1 } subscript(key: Int) -> String { return "hi" } func getSomething() -> Int { return 2 } func getSomething() -> String { return "hey" } } 

testing:

  let obj = MyClass() //let x = obj[99] // Doesn't compile: "Multiple candidates fail to match based on result type" let result1: String = obj[123] print("result1 \(result1)") // prints "result1 hi" let result2: Int = obj[123] print("result2 \(result2)") // prints "result2 1" //let x = obj.getSomething() // Doesn't compile: "Ambiguous use of 'getSomething'" let result3: String = obj.getSomething() print("result3 \(result3)") // prints "result3 hey" let result4: Int = obj.getSomething() print("result4 \(result4)") // prints "result4 2" 

这在哪里logging?

至于subscript

语言参考/声明/下标声明

只要参数或返回types与重载的参数或返回types不同,就可以在声明的types中重载下标声明。

语言指南/下标/下标选项

一个类或结构可以根据需要提供尽可能多的下标实现,并且将使用适当的下标,这取决于使用下标的下标大括号中包含的值或值的types

我找不到任何关于重载方法或函数的官方文档。 但在Swift博客中:

用Swift REPL / Redefinition或Overload重新定义一切?

请记住,Swift允许函数重载,即使两个签名只在返回types中有所不同。

函数的types由其参数的types和返回值的types决定,编译器可以通过它们的types来消除类似命名的函数 – 在你的例子中:

 subscript(key: Int) -> Int { return 1 } 

…有types(Int) -> Int

 subscript(key: Int) -> String { return "hi" } 

…有types(Int) -> String

– 虽然它们的命名方式相似,但是编译器可以通过如何分配返回值来推断哪一个被调用(或者由于这是一个subscript ,通过将哪个值分配给该下标)

继续:

 func getSomething() -> Int { return 2 } 

…有type () -> Int

 func getSomething() -> String { return "hey" } 

…有type () -> String

注意:如果你没有给编译器提供足够的信息来推断你正在调用哪个函数,例如,如果你只是简单地调用getSomething()而不做任何返回值,它就会抱怨ambiguous use of 'getSomething'

编辑 – 啊,我现在在你的示例代码中看到,你实际上提供了一个例子,在这种情况下:)通过将返回值分配给您没有指定types的常量( let x = getSomething() )编译器没有足够的信息来确定你正在调用哪个函数

编辑 编辑 – 注意,在我开始说“ 编译器可以通过types命名类似名字的函数来消除歧义 ”的情况下,函数名称由以下内容确定:(1)函数的标识符,(2)函数的外部参数的标识符名称 – 例如,虽然以下两个函数都具有相同的types和函数标识符,但它们是不同的函数,并且具有不同的函数名称,因为它们的外部参数名称使用不同的标识符:

 func getSomething(thing: String, howMany: Int) -> String 

…有type (String, Int) -> String ,并且被命名为getSomething(_:howMany:)

 func getSomething(thing: String, howManyTimes: Int) -> String 

…有type (String, Int) -> String ,并且被命名为getSomething(_:howManyTimes:)

这是Swift相当酷的一个方面。 我目前在generics类中使用它有多个下标。 这是我创build的一个操场:

 import Foundation /* Return Type Differentiation This playground illustrates a rather useful capability of Swift: The ability to differentiate methods by return type; not just argument list. In this example, we will set up multiple subscript() methods for an aggregator/façade class that will access the contained instances in various ways, depending on the return type requested. */ // This class should win the igNoble prize for poitry. struct A { let poem: [String] = ["I'm a little teapot", "bloody and cut.", "This is my handle.", "This is my "] let multiplier: UInt32 = arc4random_uniform(100) // Just a random integer from 0 to 100. } // This class has a few different data types that are set at instantiation time, and one static instance of A class B { let stringProperty: String let intProperty: Int = Int(arc4random_uniform(10)) let objectProperty: A = A() init(_ string: String) { self.stringProperty = string } // This will be used to demonstrate that we don't need to explicitly cast, if we only have one subscript method. subscript(_ ignoredIndex: Int) -> A { return self.objectProperty } } // This class acts as a façade class. It provides an interface to its contained classes as if they were direct subscripts. class C : Sequence { let aArray: [B] init() { self.aArray = [B("hut"),B("butt")] } // You can have multiple subscript() methods, differentiated by return type. subscript(_ index: Int) -> B { return self.aArray[index] } subscript(_ index: Int) -> String { return self.aArray[index].stringProperty } subscript(_ index: Int) -> UInt32 { return (self[index] as A).multiplier } subscript(_ index: Int) -> Int { return self.aArray[index].intProperty } subscript(_ index: Int) -> A { return self.aArray[index].objectProperty } // These are not simple data return subscripts. In fact, there are no Float properties, so that one is made from whole cloth. subscript(_ index: Int) -> Float { return Float(self.aArray[index].intProperty) * Float((self[index] as A).multiplier) } subscript(_ index: Int) -> [String] { var ret: [String] = [] let aInstance: B = self.aArray[index] ret = aInstance[0].poem // No need for explicit casting if we only have one subscript. ret[3] += self[index] + "." // This is allowed, as we know we're a String. return ret } // You can only have one makeIterator() method. func makeIterator() -> AnyIterator<[String]> { var nextIndex = 0 // Return a "bottom-up" iterator for the list. return AnyIterator() { if nextIndex == self.aArray.count { return nil } let ret: [String]! = self.aArray[nextIndex - 1].objectProperty.poem nextIndex += 1 return ret } } // You can have multiple methods with the same input signature, differentiated only by their output signature. func returnIndexedElement(_ atIndex: Int) -> Int { return self[atIndex] // Note no explicit casting is necessary, here. } func returnIndexedElement(_ atIndex: Int) -> UInt32 { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> A { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> B { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> Float { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> String { return self[atIndex] } func returnIndexedElement(_ atIndex: Int) -> [String] { return self[atIndex] } } let mainObject = C() // First, let's test the subscripts. // We have 3 elements, so let aObject1: A = mainObject[0] let aObject2: B = mainObject[0] let aString: String = mainObject[0] let aPoem: [String] = mainObject[0] let aInt: Int = mainObject[0] let aUInt32 = mainObject[0] as UInt32 let aFloat = mainObject[0] as Float // This will not work. You need to specify the type explicitly when using multiple subscripts, differentiated only by return type. // let failObject = mainObject[0] // However, this will work, because the class has only one subscript method defined. let aObject2_Subscript = aObject2[0] let aObject2_Poem = aObject2_Subscript.poem // Next, test the accessor methods. let bObject1: A = mainObject.returnIndexedElement(1) let bObject2: B = mainObject.returnIndexedElement(1) let bString: String = mainObject.returnIndexedElement(1) let bPoem: [String] = mainObject.returnIndexedElement(1) let bInt: Int = mainObject.returnIndexedElement(1) let bUInt32 = mainObject.returnIndexedElement(1) as UInt32 let bFloat = mainObject.returnIndexedElement(1) as Float // This will not work. You need to specify the type explicitly when using multiple methods, differentiated only by return type. // let failObject = mainObject.returnIndexedElement(1)