Was ist der Unterschied zwischen statischer Funktion und Klassenfunktion in Swift?


334

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 als definierten Elementfunktion static funcund einer als definierten Elementfunktion class func? Ist es einfach staticfür statische Funktionen von Strukturen und Aufzählungen sowie classfür Klassen und Protokolle? Gibt es noch andere Unterschiede, die man kennen sollte? Was ist der Grund für diese Unterscheidung in der Syntax selbst?


3
Es gibt wirklich keinen Unterschied. Sie konnten keine Klassenfunktion in einer Struktur verwenden, daher statische Funktion. struct func wäre ein guter Kandidat gewesen. Das ist ein bisschen nervös, wenn du mich fragst, aber gut, das sind die Worte.
Fabrice Truillot de Chambrier

2
Bonusfrage also: Kann eine Struktur einem Protokoll entsprechen, das a definiert class func? Mit den Informationen, die wir jetzt haben, scheint diese Unterscheidung ziemlich nutzlos zu sein, nicht wahr?
Jean-Philippe Pellet

3
Ja, du kannst. Seltsam, nicht wahr?
Fabrice Truillot de Chambrier

7
Der überwältigende Unterschied ist, dass Sie class funcs
Fattie

1
Zu beachten:error: class methods are only allowed within classes; use 'static' to declare a static method
Gabriel Goncalves

Antworten:


238

Ist statisch einfach für statische Funktionen von Strukturen und Aufzählungen und Klasse für Klassen und Protokolle?

Das ist der Hauptunterschied. Einige andere Unterschiede bestehen darin, dass Klassenfunktionen dynamisch ausgelöst werden und von Unterklassen überschrieben werden können.

Protokolle verwenden das Schlüsselwort class, schließen jedoch Strukturen nicht von der Implementierung des Protokolls aus, sondern verwenden stattdessen nur static. Die Klasse wurde für Protokolle ausgewählt, sodass kein drittes Schlüsselwort für die Darstellung von statisch oder klasse erforderlich sein muss.

Von Chris Lattner zu diesem Thema:

Wir haben überlegt, die Syntax zu vereinheitlichen (z. B. "type" als Schlüsselwort zu verwenden), aber das ist eigentlich nicht einfach so. Die Schlüsselwörter "Klasse" und "Statisch" sind gut für die Vertrautheit und sehr beschreibend (sobald Sie verstehen, wie + Methoden funktionieren) und öffnen die Tür, um Klassen möglicherweise wirklich statische Methoden hinzuzufügen. Die Hauptverrücktheit dieses Modells besteht darin, dass Protokolle ein Schlüsselwort auswählen müssen (und wir haben "Klasse" gewählt), aber insgesamt ist es der richtige Kompromiss.

Und hier ist ein Ausschnitt, der einige der Überschreibungsverhalten 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

4
Aha, sehr wichtiger Punkt, dass Klassenfunktionen dynamisch versendet werden! Aber könnten Sie ein solches Beispiel liefern? Sie müssten den Klassennamen irgendwo schreiben, oder? Warum also nicht statisch die Implementierung dieser Klasse auswählen?
Jean-Philippe Pellet

1
Eine weitere ergänzende Frage: Woher haben Sie das Zitat?
Jean-Philippe Pellet

Mein Verständnis ist, dass Klassenfunktionen so ziemlich genauso funktionieren wie objc + Methoden unter der Haube
Connor

1
Kann ich hier einen einfacheren Antwortlink bereitstellen? stackoverflow.com/questions/29636633/…
allenlinli

1
@ Jean-PhilippePellet Im obigen Beispiel ... wenn Sie static func myFunc()stattdessen verwenden class func myFunc, wird der folgende Fehler l angezeigt: Die statische Methode kann nicht überschrieben werden . Warum? Weil es so ist, als wäre es mit markiert worden final. Für mehr Informationen. Siehe die Antwort von nextD unten. Auch x.dynamicTypewurde jetzt durchtype(of:x)
Honey

246

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

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

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

  /* same as above
  final class func func2() -> String {
    return "func2"
  }
  */
}

static func ist das gleiche wie final class func

Da dies der Fall ist final, können wir es in der folgenden Unterklasse nicht überschreiben:

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

  // ERROR: Class method overrides a 'final` class method
  override static func func2() -> String {
    return "func2 in ClassB"
  }
}

18
du Champion, tolle Antwort ..Ich habe diesen Unterschied gesucht .. Jake !!
Abhimanyu Rathore

5
Perfekt. Beeindruckend.
Mehul

5
Dies sollte als die richtige Antwort markiert werden. Ordentlich und sauber!
abhinavroy23

1
Beste Erklärung! Dies führte mich zu einem weiteren Zweifel. Gibt es einen expliziten Grund, eine 'Klassenfunktion' zu verwenden? Ich meine, wenn Sie nur 'func' verwenden, kann es auf die gleiche Weise auch überschrieben werden. Was ist also der Unterschied?
Marcos Reboucas

1
@MarcosReboucas, wenn ich Ihre Frage richtig verstehe, class funcunterscheidet sich von normal, funcobwohl beide überschrieben werden können. Ist funcaber für eine Instanz / ein Objekt und class funckann über die Klasse wieClassA.classFunc()
Jake Lin

78

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

TL; DR Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können class, ist die Verwendung von class funcoder static funcnur eine Frage der Gewohnheit.

Spielplatzbeispiel mit Erklärung:

class Dog {
    final func identity() -> String {
        return "Once a woofer, forever a woofer!"
    }

    class func talk() -> String {
        return "Woof woof!"
    }

    static func eat() -> String {
        return "Miam miam"
    }

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

class Bulldog: Dog {
    // Can not override a final function
//    override final func identity() -> String {
//        return "I'm once a dog but now I'm a cat"
//    }

    // Can not override a "class func", but redeclare is ok
    func talk() -> String {
        return "I'm a bulldog, and I don't woof."
    }

    // Same as "class func"
    func eat() -> String {
        return "I'm a bulldog, and I don't eat."
    }

    // Normal function can be overridden
    override func sleep() -> String {
        return "I'm a bulldog, and I don't sleep."
    }
}

let dog = Dog()
let bullDog = Bulldog()

// FINAL FUNC
//print(Dog.identity()) // compile error
print(dog.identity()) // print "Once a woofer, forever a woofer!"
//print(Bulldog.identity()) // compile error
print(bullDog.identity()) // print "Once a woofer, forever a woofer!"

// => "final func" is just a "normal" one but prevented to be overridden nor redeclared by subclasses.


// CLASS FUNC
print(Dog.talk()) // print "Woof woof!", called directly from class
//print(dog.talk()) // compile error cause "class func" is meant to be called directly from class, not an instance.
print(Bulldog.talk()) // print "Woof woof!" cause it's called from Bulldog class, not bullDog instance.
print(bullDog.talk()) // print "I'm a bulldog, and I don't woof." cause talk() is redeclared and it's called from bullDig instance

// => "class func" is like a "static" one, must be called directly from class or subclassed, can be redeclared but NOT meant to be overridden.

// STATIC FUNC
print(Dog.eat()) // print "Miam miam"
//print(dog.eat()) // compile error cause "static func" is type method
print(Bulldog.eat()) // print "Miam miam"
print(bullDog.eat()) // print "I'm a bulldog, and I don't eat."

// NORMAL FUNC
//print(Dog.sleep()) // compile error
print(dog.sleep()) // print "Zzz"
//print(Bulldog.sleep()) // compile error
print(bullDog.sleep()) // print "I'm a bulldog, and I don't sleep."

7
Ihre Beispiele decken nicht den Fall ab, der in einer anderen Antwort als Hauptunterschied genannt wird: dynamischer Versand von classFunktionen vs. statische Bindung von Funktionen static.
Jean-Philippe Pellet

1
Gute Erklärung für das Verständnis von Funktionen.
Yucel Bayram

33
Ist nicht class funcüberschreibbar?
Iulian Onofrei

9
Wenn Sie versuchen, eine statische Methode zu überschreiben, erhalten Sie einen Fehler. Sie können jedoch eine Klassenmethode überschreiben. Siehe die akzeptierte Antwort
Honey

8
class funcist überschreibbar. Ich hätte das anders gewählt; liebe die Forschung und das Beispiel!
Ben Leggiero

52

Um eine Typvariableneigenschaft zu deklarieren, markieren Sie die Deklaration mit static Deklarationsmodifikator. Klassen können typberechnete Eigenschaften classstattdessen mit dem Deklarationsmodifikator markieren , damit Unterklassen die Implementierung der Oberklasse überschreiben können. Typeneigenschaften werden unter Typeneigenschaften erläutert.

HINWEIS
In einer Klassendeklaration das Schlüsselwortstatic hat die gleiche Wirkung wie Markierung , die Erklärung mit dem beide classund finalErklärung Modifikatoren.

Quelle: Die Swift-Programmiersprache - Typvariableneigenschaften


5
Die Frage ist nach 'static func' und 'class func'. Es wird NICHT nach Typeneigenschaften gefragt. Dies beantwortet also nicht die Frage - obwohl es wichtig ist, den Kontext dieser Schlüsselwörter auch in Bezug auf Eigenschaften zu verstehen.
Etayluz

Diese Antwort ist einfach auf die falsche Frage, vielleicht wurde sie hier versehentlich gepostet?
Fattie

15

Laut dem von Apple veröffentlichten Swift 2.2-Buch:

„Sie geben Typmethoden an, indem Sie das staticSchlüsselwort vor das Schlüsselwort func der Methode schreiben . Klassen können das classSchlüsselwort auch verwenden , damit Unterklassen die Implementierung dieser Methode durch die Oberklasse überschreiben können . “


10

Ab Swift2.0 sagt Apple:

"Stellen Sie den Anforderungen an Typeneigenschaften immer das statische Schlüsselwort voran, wenn Sie sie in einem Protokoll definieren. Diese Regel gilt auch dann, wenn den Anforderungen an Typeneigenschaften die Klasse oder das statische Schlüsselwort vorangestellt werden kann, wenn sie von einer Klasse implementiert werden:"


4

Dieses Beispiel wird jeden Aspekt klären!

import UIKit

class Parent {
    final func finalFunc() -> String { // Final Function, cannot be redeclared.
        return "Parent Final Function."
    }

    static func staticFunc() -> String { // Static Function, can be redeclared.
        return "Parent Static Function."
    }

    func staticFunc() -> String { // Above function redeclared as Normal function.
        return "Parent Static Function, redeclared with same name but as non-static(normal) function."
    }

    class func classFunc() -> String { // Class Function, can be redeclared.
        return "Parent Class Function."
    }

    func classFunc() -> String { // Above function redeclared as Normal function.
        return "Parent Class Function, redeclared with same name but as non-class(normal) function."
    }

    func normalFunc() -> String { // Normal function, obviously cannot be redeclared.
        return "Parent Normal Function."
    }
}

class Child:Parent {

    // Final functions cannot be overridden.

    override func staticFunc() -> String { // This override form is of the redeclared version i.e: "func staticFunc()" so just like any other function of normal type, it can be overridden.
        return "Child Static Function redeclared and overridden, can simply be called Child Normal Function."
    }

    override class func classFunc() -> String { // Class function, can be overidden.
        return "Child Class Function."
    }

    override func classFunc() -> String { // This override form is of the redeclared version i.e: "func classFunc()" so just like any other function of normal type, it can be overridden.
        return "Child Class Function, redeclared and overridden, can simply be called Child Normal Function."
    }

    override func normalFunc() -> String { // Normal function, can be overridden.
        return "Child Normal Function."
    }
}

let parent = Parent()
let child = Child()

// Final
print("1. " + parent.finalFunc())   // 1. Can be called by object.
print("2. " + child.finalFunc())    // 2. Can be called by object, parent(final) function will be called.
// Parent.finalFunc()               // Cannot be called by class name directly.
// Child.finalFunc()                // Cannot be called by class name directly.

// Static
print("3. " + parent.staticFunc())  // 3. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("4. " + child.staticFunc())   // 4. Cannot be called by object, this is override form redeclared version (normal function).
print("5. " + Parent.staticFunc())  // 5. Can be called by class name directly.
print("6. " + Child.staticFunc())   // 6. Can be called by class name direcly, parent(static) function will be called.

// Class
print("7. " + parent.classFunc())   // 7. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("8. " + child.classFunc())    // 8. Cannot be called by object, this is override form redeclared version (normal function).
print("9. " + Parent.classFunc())   // 9. Can be called by class name directly.
print("10. " + Child.classFunc())   // 10. Can be called by class name direcly, child(class) function will be called.

// Normal
print("11. " + parent.normalFunc())  // 11. Can be called by object.
print("12. " + child.normalFunc())   // 12. Can be called by object, child(normal) function will be called.
// Parent.normalFunc()               // Cannot be called by class name directly.
// Child.normalFunc()                // Cannot be called by class name directly.

/*
 Notes:
 ___________________________________________________________________________
 |Types------Redeclare------Override------Call by object------Call by Class|
 |Final----------0--------------0---------------1------------------0-------|
 |Static---------1--------------0---------------0------------------1-------|
 |Class----------1--------------1---------------0------------------1-------|
 |Normal---------0--------------1---------------1------------------0-------|
 ---------------------------------------------------------------------------

 Final vs Normal function: Both are same but normal methods can be overridden.
 Static vs Class function: Both are same but class methods can be overridden.
 */

Ausgabe: Alle Arten von Funktionen ausgeben


-6

Dies wird als Typmethode bezeichnet und wie Instanzmethoden mit Punktsyntax aufgerufen. Sie rufen jedoch Typmethoden für den Typ auf, nicht für eine Instanz dieses Typs. So rufen Sie eine Typmethode für eine Klasse namens SomeClass auf:


1
Klasse SomeClass {Klasse func someTypeMethod () {// Implementierung der Typmethode geht hier}} SomeClass.someTypeMethod ()
Kumar Utsav

Dies beantwortet die Frage überhaupt nicht. Er fragte nach dem Unterschied zwischen staticund classSchlüsselwörtern.
Doug McBride
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.