442 Stimmen

Was ist der Unterschied zwischen static func und class func in Swift?

Ich kann diese Definitionen in der Swift-Bibliothek sehen:

extension Bool : BooleanLiteralConvertible {
    static func convertFromBooleanLiteral(value: Bool) -> Bool
}

protocol BooleanLiteralConvertible {
    typealias BooleanLiteralType
    class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}

Was ist der Unterschied zwischen einer Member-Funktion, die als static func definiert ist, und einer anderen, die als class func definiert ist? Ist es einfach so, dass static für statische Funktionen von Strukturen und Enums steht, und class für Klassen und Protokolle? Gibt es andere Unterschiede, die man kennen sollte? Was ist der Grund für diese Unterscheidung in der Syntax selbst?

393voto

Jake Lin Punkte 10558

Um es klarer zu machen, mache ich hier ein Beispiel:

class ClassA {
    class func func1() -> String {
        return "func1"
    }

    static func func2() -> String {
        return "func2"
    }
}

/* das Gleiche wie oben
    final class func func2() -> String {
        return "func2"
    }
*/

static func ist das Gleiche wie final class func

Weil es final ist, können wir es nicht in der Unterklasse überschreiben, wie unten:

class ClassB: ClassA {
    override class func func1() -> String {
        return "func1 in ClassB"
    }

    // FEHLER: Klassenmethode überschreibt eine 'final` Klassenmethode
    override static func func2() -> String {
        return "func2 in ClassB"
    }
}

295voto

Connor Punkte 62453

Ist es einfach so, dass "static" für statische Funktionen von Strukturen und Enums und "class" für Klassen und Protokolle verwendet wird?

Das ist der Hauptunterschied. Einige andere Unterschiede sind, dass Klassenfunktionen dynamisch verteilt werden und von Unterklassen überschrieben werden können.

Protokolle verwenden das Schlüsselwort "class", aber das schließt nicht aus, dass Strukturen das Protokoll implementieren, sie verwenden einfach statisch. "Class" wurde für Protokolle gewählt, damit es kein drittes Schlüsselwort geben müsste, um statisch oder klassisch darzustellen.

Von Chris Lattner zu diesem Thema:

Wir haben in Betracht gezogen, die Syntax zu vereinheitlichen (z.B. durch Verwendung von "type" als Schlüsselwort), aber das vereinfacht die Dinge nicht wirklich. Die Schlüsselwörter "class" und "static" sind gut für die Bekanntheit und sind ziemlich beschreibend (wenn Sie erst einmal verstehen, wie +Methoden funktionieren) und öffnen die Tür für die mögliche Hinzufügung von wirklich statischen Methoden zu Klassen. Das Hauptmanko dieses Modells ist, dass Protokolle ein Schlüsselwort wählen müssen (und wir haben "class" gewählt), aber im Großen und Ganzen ist es der richtige Kompromiss.

Und hier ist ein Ausschnitt, der etwas vom Überschreibverhalten von Klassenfunktionen zeigt:

class MyClass {
    class func myFunc() {
        println("myClass")
    }
}

class MyOtherClass: MyClass {
    override class func myFunc() {
        println("myOtherClass")
    }
}

var x: MyClass = MyOtherClass()
x.dynamicType.myFunc() //myOtherClass
x = MyClass()
x.dynamicType.myFunc() //myClass

89voto

Thanh-Nhon Nguyen Punkte 3241

Ich habe einige Experimente auf dem Spielplatz gemacht und einige Schlussfolgerungen gezogen.

Zusammenfassung Bildbeschreibung hier eingeben

Wie Sie sehen können, ist es im Fall von class die Verwendung von class func oder static func nur eine Frage der Gewohnheit.

Beispiel im Playground mit Erklärung:

class Dog {
    final func identity() -> String {
        return "Einmal ein Winsler, immer ein Winsler!"
    }

    class func talk() -> String {
        return "Wuff wuff!"
    }

    static func eat() -> String {
        return "Mjam mjam"
    }

    func sleep() -> String {
        return "Zzz"
    }
}

class Bulldog: Dog {
    // Kann keine finale Funktion überschreiben
//    override final func identity() -> String {
//        return "Einmal ein Hund, aber jetzt bin ich eine Katze"
//    }

    // Kann keine "class func" überschreiben, aber neu deklarieren geht
    func talk() -> String {
        return "Ich bin ein Bulldog, und ich winsele nicht."
    }

    // Das gleiche wie "class func"
    func eat() -> String {
        return "Ich bin ein Bulldog, und ich esse nicht."
    }

    // Normale Funktion kann überschrieben werden
    override func sleep() -> String {
        return "Ich bin ein Bulldog, und ich schlafe nicht."
    }
}

let hund = Dog()
let bulldogge = Bulldog()

// FINALE FUNKTION
//print(Dog.identity()) // Kompilierfehler
print(hund.identity()) // druckt "Einmal ein Winsler, immer ein Winsler!"
//print(Bulldog.identity()) // Kompilierfehler
print(bulldogge.identity()) // druckt "Einmal ein Winsler, immer ein Winsler!"

// => "final func" ist nur eine "normale" Funktion, die jedoch davon abhält, von Unterklassen überschrieben oder neu deklariert zu werden.

// CLASS FUNC
print(Dog.talk()) // druckt "Wuff wuff!", direkt von der Klasse aufgerufen
//print(hund.talk()) // Kompilierfehler, da "class func" dazu gedacht ist, direkt von der Klasse und nicht von einer Instanz aufgerufen zu werden.
print(Bulldog.talk()) // druckt "Wuff wuff!", da es von der Klasse Bulldog und nicht von der Instanz bullDogge aufgerufen wird.
print(bulldogge.talk()) // druckt "Ich bin ein Bulldog, und ich winsele nicht.", da talk() neu deklariert wird und von der Instanz bullDogge aufgerufen wird

// => "class func" ist wie eine "static" Funktion, die direkt von der Klasse oder einer abgeleiteten Klasse aufgerufen werden muss, neu deklariert werden kann, aber nicht zur Überschreibung gedacht ist.

// STATIC FUNC
print(Dog.eat()) // druckt "Mjam mjam"
//print(hund.eat()) // Kompilierfehler, da "static func" eine Typmethode ist
print(Bulldog.eat()) // druckt "Mjam mjam"
print(bulldogge.eat()) // druckt "Ich bin ein Bulldog, und ich esse nicht."

// NORMALE FUNKTION
//print(Dog.sleep()) // Kompilierfehler
print(hund.sleep()) // druckt "Zzz"
//print(Bulldog.sleep()) // Kompilierfehler
print(bulldogge.sleep()) // druckt "Ich bin ein Bulldog, und ich schlafe nicht."

54voto

NexD. Punkte 784

Um eine Typvariableneigenschaft zu deklarieren, kennzeichnen Sie die Deklaration mit dem Deklarationsmodifizierer static. Klassen können stattdessen Typberechnungseigenschaften mit dem Deklarationsmodifizierer class markieren, um Unterklassen zu ermöglichen, die Implementierung der Superklasse zu überschreiben. Typvariablen werden in den Typvariablen behandelt.

HINWEIS
In einer Klassendeklaration hat das Schlüsselwort static den gleichen Effekt wie die Markierung der Deklaration mit den Deklarationsmodifizierern class und final.

Quelle: Die Swift-Programmiersprache - Typvariableigenschaften

28voto

Habibur Rahman Punkte 319

Sowohl die statische als auch die Klassen Schlüsselwörter ermöglichen es uns, Methoden an einer Klasse anstatt an Instanzen einer Klasse anzuhängen. Zum Beispiel könnten Sie eine Studentenklasse mit Eigenschaften wie Name und Alter erstellen und dann eine statische Methode numberOfStudents erstellen, die von der Studentenklasse selbst und nicht von einzelnen Instanzen besessen wird.

Der Unterschied zwischen statisch und Klassen liegt darin, wie sie die Vererbung unterstützen. Wenn Sie eine statische Methode erstellen, gehört sie der Klasse und kann von Unterklassen nicht geändert werden, während sie bei Verwendung von Klassen überschrieben werden kann, wenn nötig.

Hier ist ein Beispielcode:

class Vehicle {
    static func getCurrentSpeed() -> Int {
        return 0
    }

    class func getCurrentNumberOfPassengers() -> Int {
        return 0
    } 
}

class Bicycle: Vehicle {
    //Dies ist nicht erlaubt
    //Compilerfehler: "Kann statische Methode nicht überschreiben"
    //static override func getCurrentSpeed() -> Int {
        //return 15
    //}

    class override func getCurrentNumberOfPassengers() -> Int {
        return 1
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X