class - programacion - ¿Cuál es la diferencia entre función estática y función de clase en Swift?
tipos de datos en swift (7)
Puedo ver estas definiciones en la biblioteca de 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 func
y otra definida como class func
? ¿Es simplemente que static
es para funciones estáticas de estructuras y enumeraciones, y class
para clases y protocolos? ¿Hay alguna otra diferencia que uno deba saber? ¿Cuál es la razón para tener esta distinción en la propia sintaxis?
¿Es simplemente que estático es para funciones estáticas de estructuras y enumeraciones, y clase para clases y protocolos?
Esa es la principal diferencia. Algunas otras diferencias son que las funciones de clase se distribuyen dinámicamente y pueden ser reemplazadas por subclases.
Los protocolos utilizan la palabra clave de clase, pero no excluyen las estructuras de la implementación del protocolo, en su lugar solo usan estática. La clase se eligió para los protocolos, por lo que no tendría que haber una tercera palabra clave para representar estática o clase.
De Chris Lattner sobre este tema:
Consideramos la posibilidad de unificar la sintaxis (por ejemplo, usar "tipo" como palabra clave), pero eso no es realmente simple. Las palabras clave "clase" y "estática" son buenas para la familiaridad y son bastante descriptivas (una vez que entiendes cómo funcionan los métodos +), y abres la puerta para agregar métodos verdaderamente estáticos a las clases. La rareza principal 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 algunos de los comportamientos 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
Para declarar una propiedad de variable de tipo, marque la declaración con el modificador de declaración
static
. Las clases pueden marcar propiedades computadas de tipo con el modificador de declaración declass
lugar de permitir que las subclases anulen la implementación de la superclase. Las propiedades de tipo se discuten en Propiedades de tipo.NOTA
En una declaración de clase, la palabra clavestatic
tiene el mismo efecto que marcar la declaración con los modificadores de declaraciónfinal
y declass
.
Fuente: El lenguaje de programación Swift - Propiedades de tipo variable
Desde Swift2.0, Apple dice:
"Siempre prefije los requisitos de propiedad de tipo con la palabra clave estática cuando los defina en un protocolo. Esta regla se aplica a pesar de que los requisitos de propiedad de tipo pueden tener el prefijo de la clase o la palabra clave estática cuando la implementa una clase:"
Hice algunos experimentos en el patio y obtuve algunas conclusiones.
Como puede ver, en el caso de la class
, el uso de class func
de class func
o static func
es solo una cuestión de hábito.
Ejemplo de patio de recreo 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."
La principal diferencia es que las estructuras son tipos de valor y las clases son tipos de referencia.
Cuando hace una copia de un tipo de valor, copia todos los datos de lo que está copiando en la nueva variable. Son 2 cosas separadas y cambiar una no afecta a la otra.
Cuando hace una copia de un tipo de referencia, la nueva variable se refiere a la misma ubicación de memoria que está copiando. Esto significa que cambiar uno cambiará al otro ya que ambos se refieren a la misma ubicación de memoria
Para ser más claros, hago 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 func
es la misma que final class func
Debido a que es final
, no podemos anularlo en la subclase de la siguiente manera:
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"
}
}
Según el libro Swift 2.2 publicado por apple:
“Usted indica los métodos de tipo escribiendo la palabra clave static
antes de la palabra clave func del método. Las clases también pueden usar la palabra clave de class
para permitir que las subclases anulen la implementación de ese método por la superclase ".