2016-07-12 10 views
2

Ich habe Protokoll und seine Umsetzung in Swift geschrieben:Standardparameter als generischer Typ

protocol P { 
} 

struct A: P { 
} 

Protokoll ist als generischer Typ für eine Funktion verwendet:

func foo<T: P>(param: T) { 
} 

func foo() { 
    foo(param: A()) 
} 

Bisher funktioniert alles einwandfrei. Aber ich möchte A() als Standardparameter der gegebenen Funktion setzen:

func foo<T: P>(param: T = A()) { 
} 

Leider mit folgenden Fehler:

Default argument value of type 'A' cannot be converted to type 'T'.

Oder

func foo<T: P>(param: T = A() as P) { 
} 

,

let a: P = A() 
func foo<T: P>(param: T = a) { 
} 

Rückgabe:

Default argument value of type 'P' cannot be converted to type 'T'

Oder

func foo<T: P>(param: T = A() as T) { 
} 

Returns:

'A' is not convertible to 'T'; did you mean to use 'as!' to force downcast?

Was ich falsch mache? Wo ist das Problem?

Ich will keine Gewalt Guss wie diese verwenden:

func foo<T: P>(param: T = A() as! T) { 
} 

Vielen Dank im Voraus.

Antwort

3

Sie versuchen, ein nicht-generisches Standardargument in einer generischen Funktion zu erzwingen: Sie sollten wahrscheinlich darüber nachdenken, was Sie hier erreichen möchten.

Aus Gründen der Diskussion Sie könnte umfasst eine versuchte Besetzung von A()-T in Ihrer Funktion Unterschrift, aber Sie würden das Argument Typen optional ändern müssen fehlgeschlagen Konvertierung (nil) zu ermöglichen, z.B.

func foo<T: P>(param: T? = (A() as? T)) { } 

Eine sinnvolle Alternative ist, einschließlich - zusätzlich zu Ihrer generischen Funktion - eine konkrete nicht-generische Funktion für Fälle, in denen T sind A (konkrete Funktionen Vorrang vor generischen nehmen), in dem Fall, dass Sie umfassen können das Standardargument A() in der Funktionssignatur der konkreten Funktion. Z.B.

protocol P { } 
struct A: P { } 
extension Int: P { } 

func foo<T: P>(param: T) { print("called generic foo") } 
func foo(param: A = A()) { print("called A specific foo") } 

foo() // called A specific foo (making use of default arg) 
foo(A()) // called A specific foo 
foo(1) // called generic foo 

Beachten Sie, dass die nicht-generic foo obwohl A genannt wird, entspricht P (A gemacht Verwendung der Gattungs foo haben könnte): es gibt keinen Konflikt hier als die konkrete Funktion Vorrang.

Wenn Sie auf der anderen Seite wollen nur Ihre generische Funktion erlauben, ohne das einzelne Argument (d. H.(unter Verwendung eines Standardarguments) können Sie einen Entwurf eines einfachen Initialisierers in P einfügen, mit dem Sie eine Instanz des generischen Typs als Standardargument initialisieren können; siehe @Sulthan:s answer.

1

Das einzige, was Sie brauchen, ist eine Voraussetzung für eine initializer dem Protokoll hinzuzufügen:

protocol P { 
    init() 
} 

struct A: P { 
    var x: Int 

    init() { 
     x = 10 
    } 
} 

func foo<T: P>(param param: T = T()) { 
} 

Allerdings müssen Sie ein anderes Problem. Der Typ des übergebenen Parameters entscheidet über den Typ des generischen, so dass Sie den generischen Typ irgendwie anders angeben müssen.