Swift: sobrecargas de método que solo difieren en el tipo de retorno

Sigo viendo classs Swift donde se definen dos methods que solo difieren en el tipo de retorno. No estoy acostumbrado a trabajar en idiomas donde esto está permitido (Java, C #, etc.), así que busqué la documentation que describe cómo funciona esto en Swift. No he encontrado absolutamente nada en ninguna parte. Hubiera esperado una sección completa en el libro Swift. ¿Dónde está documentado esto?

Aquí hay un ejemplo de lo que estoy hablando (estoy usando 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" } } 

Prueba:

  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" 

¿Dónde está documentado esto?

En cuanto al subscript :

Referencia de lenguaje / statement / statement de subíndice

Puede sobrecargar una statement de subíndice en el tipo en el que se declara, siempre que los parameters o el tipo de devolución difieran del que está sobrecargando.

Guía de idiomas / Subíndices / Opciones de subíndice

Una class o estructura puede proporcionar la cantidad de implementaciones de subíndices que necesite, y el subíndice apropiado que se utilizará se inferirá en function de los types de valores o valores que están contenidos en los subprocesss de subíndice en el punto en que se utiliza el subíndice.

No puedo encontrar ningún documento oficial sobre methods o funciones de sobrecarga. pero en el blog Swift:

¿Redefinir todo con la REPL Swift / networkingefinición o sobrecarga?

Tenga en count que Swift permite la sobrecarga de funciones incluso cuando dos firmas difieren solo en su tipo de retorno.

El tipo de una function está determinado por el tipo de sus arguments y el tipo de su valor de retorno, y el comstackdor puede desambiguar las funciones denominadas de manera similar por su tipo, a partir de su ejemplo:

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

… tiene tipo (Int) -> Int

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

… tiene el tipo (Int) -> String

– a pesar de que se les denomina de forma similar, el comstackdor puede inferir a cuál se le llama por cómo se asigna el valor de retorno (o dado que se trata de un subscript , por el valor que se le asigna a ese subíndice)

continuo:

 func getSomething() -> Int { return 2 } 

… tiene tipo () -> Int

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

… tiene tipo () -> String

nota: donde podría meterse en problemas es si no proporciona el comstackdor suficiente información para deducir qué function está llamando, por ejemplo, si simplemente llamó a getSomething() sin hacer nada con su valor de retorno, se quejaría de ambiguous use of 'getSomething'

EDITAR : ah, veo en su código de muestra ahora que de hecho proporciona un ejemplo donde este es el caso 🙂 asignando el valor de retorno a una constante para la que no ha especificado el tipo ( let x = getSomething() ) no hay suficiente información para que el comstackdor resuelva qué function está llamando

EDIT EDIT – tenga en count que cuando empiezo diciendo ' el comstackdor puede desambiguar las funciones nombradas de manera similar por su tipo ', los nombres de las funciones están determinados por: (1) el identificador de la function, junto con (2) los identificadores del parámetro externo de la function nombres, por ejemplo, aunque las dos funciones siguientes tienen el mismo tipo y identificador de function, son funciones diferentes y tienen diferentes nombres de funciones porque difieren en los identificadores utilizados para sus nombres de parameters externos:

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

… tiene el tipo (String, Int) -> String y se denomina getSomething(_:howMany:)

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

… tiene el tipo (String, Int) -> String , y se denomina getSomething(_:howManyTimes:)

Este es un aspecto bastante genial de Swift. Actualmente lo uso en una class genérica para tener múltiples subíndices. Aquí hay un patio de juegos que creé para prepararlo:

 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(_ ignonetworkingIndex: 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)