¿Cuál es la diferencia entre función estática y función de clase en Swift?

Resuelto Jean-Philippe Pellet asked hace 10 años • 9 respuestas

Puedo ver estas definiciones en la biblioteca Swift:

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

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

¿Cuál es la diferencia entre una función miembro definida como static funcy otra definida como class func? ¿Es simplemente staticpara funciones estáticas de estructuras y enumeraciones, y classpara clases y protocolos? ¿Existen otras diferencias que debamos conocer? ¿Cuál es la razón para tener esta distinción en la sintaxis misma?

Jean-Philippe Pellet avatar Aug 06 '14 16:08 Jean-Philippe Pellet
Aceptado

Para ser más claro, pongo un ejemplo aquí,

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 funces igual quefinal class func

Debido a que lo es final, no podemos anularlo en la subclase como se muestra a continuación:

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"
    }
}
Jake Lin avatar Mar 03 '2016 01:03 Jake Lin

¿Es simplemente que static es para funciones estáticas de estructuras y enumeraciones, y class para clases y protocolos?

Esa es la principal diferencia. Algunas otras diferencias son que las funciones de clase se distribuyen dinámicamente y las subclases pueden anularlas.

Los protocolos usan la palabra clave class, pero no excluye que las estructuras implementen el protocolo, simplemente usan static en su lugar. Se eligió clase para los protocolos para que no tuviera que haber una tercera palabra clave para representar estática o clase.

De Chris Lattner sobre este tema:

Consideramos unificar la sintaxis (por ejemplo, usar "tipo" como palabra clave), pero en realidad eso no simplifica las cosas. Las palabras clave "clase" y "estática" son buenas para familiarizarse y son bastante descriptivas (una vez que comprenda cómo funcionan los métodos +), y abren la puerta para agregar potencialmente métodos verdaderamente estáticos a las clases. La principal rareza de este modelo es que los protocolos tienen que elegir una palabra clave (y nosotros elegimos "clase"), pero en general es la compensación correcta.

Y aquí hay un fragmento que muestra parte del comportamiento de anulación de las funciones de clase:

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
Connor Pearson avatar Aug 06 '2014 10:08 Connor Pearson

Hice algunos experimentos en el patio de recreo y saqué algunas conclusiones.

TL;DR ingrese la descripción de la imagen aquí

Como puedes ver, en el caso de class, el uso de class funco static funces sólo una cuestión de costumbre.

Ejemplo de parque infantil con explicación:

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."
Thanh-Nhon Nguyen avatar Jun 13 '2016 23:06 Thanh-Nhon Nguyen