2015-07-29 4 views
5

Continuo a vedere le classi Swift in cui sono definiti due metodi che differiscono solo per il tipo restituito. Non sono abituato a lavorare in lingue in cui ciò è consentito (Java, C#, ecc.), Quindi sono andato a cercare la documentazione che descrive come funziona in Swift. Non ho trovato assolutamente nulla da nessuna parte. Mi sarei aspettato un'intera sezione su di esso nel libro Swift. Dove è documentato?Swift: overload di metodi che differiscono solo nel tipo di ritorno

Ecco un esempio di cosa sto parlando (sto 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" 
    } 
} 

prova:

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" 
+4

Penso che la tua demo ci spieghi le cose abbastanza bene. Se il compilatore può determinare quale funzione usare, è permesso. Questo include non solo il nome della funzione, ma anche nomi e tipi di argomenti e anche il tipo di ritorno. Le funzioni con diverse firme contano come funzioni diverse. – Eric

risposta

7

Dove si trova questa documentata?

Per quanto riguarda subscript:

Language Reference/Declarations/Subscript Declaration

È possibile sovraccaricare una dichiarazione pedice nel tipo in cui è dichiarata, fino a quando i parametri o il tipo di ritorno differiscono dalla uno che stai sovraccaricando.

Language Guide/Subscripts/Subscript Options

Una classe o una struttura in grado di fornire come molte implementazioni pedice come ha bisogno, e il pedice appropriata da utilizzare sarà essere dedotta in base ai tipi di valore o valori che sono contenuto all'interno delle parentesi indice nel punto in cui viene utilizzato l'indice.

Non riesco a trovare documenti ufficiali su metodi o funzioni di overload. ma nel Blog Swift:

Redefining Everything with the Swift REPL/Redefinition or Overload?

Tenete a mente che Swift permette funzione di sovraccarico, anche quando due firme differiscono solo per il loro tipo di ritorno.

6

tipo di una funzione è determinata dal tipo dei suoi argomenti e il tipo del suo valore di ritorno, e il compilatore può disambiguare funzioni con nomi simili dal loro tipo - dal tuo esempio:

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

... ha digitare (Int) -> Int

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

... è digitare (Int) -> String

- così anche se sono allo stesso nome, il compilatore può dedurre quale viene chiamato da come viene assegnato il valore di ritorno (o poiché questo è un subscript, dalla quale valore viene assegnato a tale pedice)

continua:

func getSomething() -> Int { 
    return 2 
} 

... ha digitare () -> Int

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

... è digitare () -> String

nota: dove si potrebbe ottenere nei guai è se non si fornisce il compilatore informazioni sufficienti per poter dedurre che funzionano stai chiamando, ad es se semplicemente chiamato getSomething() senza fare nulla con il suo valore di ritorno, sarebbe lamentarsi ambiguous use of 'getSomething'

EDIT - Ah, vedo nel codice di esempio ora che si fa, infatti, fornire un esempio in cui questo è il caso :) assegnando il valore di ritorno ad una costante per il quale non è stato specificato il tipo (let x = getSomething()) non ci sono abbastanza informazioni per il compilatore per risolvere quale funzione si sta chiamando

EDITEDIT - notare che dove sono iniziare dicendo 'il compilatore può disambiguare i s funzioni con un nome simile al loro tipo ', i nomi delle funzioni sono determinati da: (1) l'identificatore per la funzione, insieme a (2) gli identificatori per i nomi dei parametri esterni della funzione, ad esempio, ad es. se i due seguente funzione entrambi hanno lo stesso tipo e l'identificatore funzione, sono funzioni diverse e hanno diversi nomi funzione perché differiscono per gli identificatori utilizzati per i loro nomi di parametri esterni:

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

...ha tipo (String, Int) -> String, e prende il nome getSomething(_:howMany:)

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

... è di tipo (String, Int) -> String, e prende il nome getSomething(_:howManyTimes:)

0

Questo è un aspetto abbastanza interessante di Swift. Attualmente sto usando in una classe generica per avere più indici. Ecco un parco giochi che ho creato per officina:

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)