web-dev-qa-db-fra.com

Quelle est la différence entre static func et class func dans Swift?

Je peux voir ces définitions dans la bibliothèque Swift:

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

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

Quelle est la différence entre une fonction membre définie par static func et une autre définie par class func? Est-ce simplement que static est pour des fonctions statiques de structs et d'énums, et class pour des classes et des protocoles? Existe-t-il d'autres différences qu'il convient de connaître? Quelle est la raison d'avoir cette distinction dans la syntaxe elle-même?

300

Est-ce simplement que statique est pour les fonctions statiques de structs et d’énums, et classe pour les classes et les protocoles?

C'est la principale différence. Certaines autres différences sont que les fonctions de classe sont distribuées dynamiquement et peuvent être remplacées par des sous-classes.

Les protocoles utilisent le mot-clé class, mais cela n'exclut pas les structures d'implémenter le protocole, elles utilisent simplement statique. La classe a été choisie pour les protocoles, il n'y aurait donc pas besoin d'un troisième mot clé pour représenter statique ou classe.

De Chris Lattner sur ce sujet:

Nous avons envisagé d’unifier la syntaxe (par exemple, en utilisant "type" comme mot clé), mais cela ne signifie pas simplement des choses. Les mots-clés "class" et "static" sont bons pour la connaissance et sont assez descriptifs (une fois que vous comprenez le fonctionnement des méthodes), et ouvrent la porte à l'ajout potentiel de méthodes réellement statiques aux classes. La principale bizarrerie de ce modèle est que les protocoles doivent choisir un mot clé (et nous avons choisi "classe"), mais dans l’ensemble, c’est le bon compromis.

Et voici un extrait qui montre une partie du comportement de substitution des fonctions de classe:

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
206
Connor

Pour être plus clair, je fais un exemple ici,

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 est identique à final class func

Comme il s'agit de final, nous ne pouvons pas le remplacer dans la sous-classe ci-dessous:

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"
  }
}
205
Jake Lin

J'ai fait des expériences sur un terrain de jeu et j'ai tiré quelques conclusions.

TL; DR enter image description here

Comme vous pouvez le constater, dans le cas de class, l’utilisation de class func ou static func n’est qu’une question d’habitude.

Exemple de terrain de jeu avec explication:

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."
70
Nhon Nguyen

Pour déclarer une propriété de variable de type, marquez la déclaration avec le modificateur de déclaration static. Les classes peuvent marquer les propriétés de type calculées avec le modificateur de déclaration class pour permettre aux sous-classes de remplacer l’implémentation de la superclasse. Les propriétés de type sont discutées dans Propriétés du type.

NOTE
Dans une déclaration de classe, le mot clé static a le même effet que le marquage de la déclaration avec les deux modificateurs de déclaration class et final.

Source: Le Swift Langage de programmation - Propriétés de la variable de type

52
NexD.

Selon le Swift 2.2 Livre publié par Apple:

“Vous indiquez les méthodes de type en écrivant le mot clé static avant le mot clé func de la méthode. Les classes peuvent également utiliser le mot clé classpour permettre aux sous-classes de remplacer l'implémentation de la méthode par la superclasse. ”

13
Milad

Dans Swift2.0, Apple dit:

"Toujours préfixer les exigences de propriété de type avec le mot clé static lorsque vous les définissez dans un protocole. Cette règle s'applique même si les exigences de propriété de type peuvent être préfixées avec le mot clé class ou static lorsqu'elles sont implémentées par une classe:"

10
Jacky