2015-07-29 10 views
5

Wciąż widzę klasy Swift, w których zdefiniowano dwie metody różniące się tylko typem zwrotnym. Nie jestem przyzwyczajony do pracy w językach, w których jest to dozwolone (Java, C#, itp.), Więc poszedłem szukać dokumentacji, która opisuje, jak to działa w Swift. Nigdzie niczego nie znalazłem. Spodziewałbym się całej sekcji w książce Swift. Gdzie jest to udokumentowane?Swift: przeciążenia metod różniące się tylko typem zwrotu

Oto przykład tego, co mówię (używam 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

Wydaje mi się, że twoje demo dość dobrze wyjaśnia rzeczy. Jeśli kompilator może określić, której funkcji użyć, jest to dozwolone. Obejmuje to nie tylko nazwę funkcji, ale także nazwy i typy argumentów, a także typ zwracany. Funkcje z różnymi sygnaturami liczą się jako różne funkcje. – Eric

Odpowiedz

7

Gdzie jest to udokumentowane?

chodzi o subscript:

Language Reference/Declarations/Subscript Declaration

Można przeciążać deklarację indeksie w rodzaju, w którym została zadeklarowana, jak długo parametrów lub zwracanego typu różnią się od jeden przeciążasz.

Language Guide/Subscripts/Subscript Options

Klasa lub struktura może dostarczyć jak najwięcej indeksy dolne implementacje ile potrzebuje, i odpowiedni indeks być wykorzystywane będą wnioskować na podstawie typów wartości lub wartości, które są zawarte w nawiasach dolnych w miejscu, w którym używany jest indeks dolny.

Nie mogę znaleźć żadnych oficjalnych dokumentów dotyczących przeciążania metod lub funkcji. ale w Swift blogu:

Redefining Everything with the Swift REPL/Redefinition or Overload?

Należy pamiętać, że Swift pozwala funkcję przeciążenia nawet gdy dwa podpisy różnią się tylko w ich typ zwracany.

6

typ funkcji jest określona przez typ jego argumentów i typu zwracanej wartości, a kompilator może rozróżniać funkcje o podobnej nazwie według ich typu - z Twojego przykładu:

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

... ma typ (Int) -> Int

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

... ma typ (Int) -> String

- więc chociaż są podobnie nazwane, kompilator może wnioskować których jeden jest nazywany przez jak wartość zwracana jest przypisana (albo ponieważ jest to subscript, przez co wartość jest przypisana do tego indeksu)

kontynuując:

func getSomething() -> Int { 
    return 2 
} 

... ma typ () -> Int

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

... ma typ () -> String

uwaga: gdzie można dostać się w kłopoty jest, jeśli nie zapewniają wystarczającej ilości informacji dla kompilatora to wydedukować, która funkcja dzwonisz, np jeśli po prostu nazywa getSomething() nie robiąc nic ze swej wartości zwracanej, byłoby narzekać ambiguous use of 'getSomething'

EDIT - Ach, widzę w kodzie próbki teraz, że w rzeczywistości stanowić przykład, gdzie jest to sprawa :) poprzez przypisanie wartości zwracanej do stałej, dla których nie określono typ (let x = getSomething()) nie ma wystarczająco dużo informacji kompilator uporządkować które funkcjonują dzwonisz

EDITEDIT - pamiętać, że gdzie ja zacznij od stwierdzenia "kompilator może disambiguate s nazwane funkcje według ich typów ', nazwy funkcji są określane przez: (1) identyfikator funkcji wraz z (2) identyfikatorami zewnętrznych nazw parametrów funkcji - np. choć po dwóch funkcji oba mają ten sam typ i identyfikator funkcji, są one różne funkcje i mają różne nazwy funkcji, ponieważ różnią się one w identyfikatorów używanych do ich nazw parametrów zewnętrznych:

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

...ma typ (String, Int) -> String, i nazywa getSomething(_:howMany:)

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

... ma typ (String, Int) -> String, i nazywa getSomething(_:howManyTimes:)

0

To dość fajny aspekt Swift. Obecnie używam go w klasie ogólnej, aby mieć wiele indeksów dolnych. Oto plac zabaw, który stworzyłem, aby go przetestować:

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) 
Powiązane problemy