2015-07-29 6 views
5

Ich sehe immer Swift-Klassen, in denen zwei Methoden definiert sind, die sich nur im Rückgabetyp unterscheiden. Ich bin es nicht gewohnt, in Sprachen zu arbeiten, in denen dies erlaubt ist (Java, C#, usw.), also suchte ich nach der Dokumentation, die beschreibt, wie dies in Swift funktioniert. Ich habe absolut nichts gefunden. Ich hätte im Swift-Buch einen ganzen Abschnitt darüber erwartet. Wo ist das dokumentiert? HierSwift: Methodenüberladungen, die sich nur im Rückgabetyp unterscheiden

ist ein Beispiel dafür, was ich rede (Ich verwende 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" 
    } 
} 

Test:

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

Ich denke, dass Ihre Demo dort Dinge ziemlich gut erklärt. Wenn der Compiler bestimmen kann, welche Funktion zu verwenden ist, ist es erlaubt. Dies umfasst nicht nur den Namen der Funktion, sondern auch Namen und Typen von Argumenten sowie den Rückgabetyp. Funktionen mit unterschiedlichen Signaturen zählen als unterschiedliche Funktionen. – Eric

Antwort

7

genannt Wo dies dokumentiert ist?

Was subscript:

Language Reference/Declarations/Subscript Declaration

Sie einen Index Erklärung in der Art überlasten kann, in dem es deklariert wird, solange die Parameter oder der Rückgabetyp unterscheiden sich von den einen, den du überlädst.

Language Guide/Subscripts/Subscript Options

Eine Klasse oder Struktur kann so viele Index-Implementierungen, wie es braucht, und der entsprechende Index verwendet werden, wird auf der Grundlage der Arten des Wertes oder Werte abgeleitet werden, die in den Index Klammern an dem Punkt enthalten, dass der Index verwendet wird.

Ich kann keine offiziellen Dokumente über Überladungsmethoden oder Funktionen finden. aber in der Swift Blog:

Redefining Everything with the Swift REPL/Redefinition or Overload?

Beachten Sie, dass Swift Funktion Überlastung erlaubt, selbst wenn zwei Signaturen unterscheiden sich nur in ihren Rückgabetyp.

6

Der Typ einer Funktion vom Typ bestimmt wird, seiner Argumente und der Art seines Rückgabewerts, und der Compiler kann ähnlich benannte Funktionen nach ihrem Typ disambiguieren - aus Ihrem Beispiel:

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

... hat (Int) -> Int Typ

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

... (Int) -> String

hat geben - so, obwohl sie ähnlich benannt sind, kann der Compiler ableiten, die man durch, wie der Rückgabewert aufgerufen wird wird zugewiesen (oder, da dies ein subscript, mit welchem ​​Wert in diesem Index zugeordnet wird)

fort:

func getSomething() -> Int { 
    return 2 
} 

... hat () -> Int

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

... Typ hat () -> String

Note geben: wo man sich in Schwierigkeiten geraten könnte, ist, wenn Sie den Compiler genug Informationen nicht zur Verfügung stellen für sie die Funktion ableiten Du rufst an, z wenn Sie einfach getSomething() ohne etwas zu tun mit ihrem Rückgabewert genannt, wäre es etwa ambiguous use of 'getSomething'

EDIT beschweren - ah, ich sehe in Ihrem Beispielcode jetzt, dass Sie in der Tat ein Beispiel geben, wo dies der Fall ist :) durch den Rückgabewert auf einen konstanten zuweisen, für die Sie nicht den Typ festgelegt haben (let x = getSomething()) gibt es nicht genügend Informationen für den Compiler zu klären, welche Funktion Sie

EDITEDIT fordern - beachten Sie, dass, wo ich beginnen mit der Angabe 'der Compiler kann s disambiguieren ähnliche Funktionen nach ihrem Typ ', Funktionsnamen werden bestimmt durch: (1) die Kennung für die Funktion zusammen mit (2) den Kennungen für die externen Parameternamen der Funktion - so z.B. obwohl die beiden folgenden beide Funktion die gleiche Art und Funktionskennzeichen haben, sind sie unterschiedliche Funktionen und unterschiedliche Funktionsnamen haben, weil sie in den Kennungen für ihre externen Parameternamen verwendet werden, unterscheiden:

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

...hat (String, Int) -> String Typ und wird getSomething(_:howMany:)

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

namens ... (String, Int) -> String Typ hat, und ist getSomething(_:howManyTimes:)

0

Dies ist ein ziemlich cooler Aspekt von Swift. Ich benutze es derzeit in einer generischen Klasse, um mehrere Indizes zu haben. Hier ist ein Spielplatz, den ich erstellt habe, um es zu bearbeiten:

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) 
Verwandte Themen