В чем разница между статическим func и классом func в Swift?
Я вижу эти определения в библиотеке Swift:
extension Bool : BooleanLiteralConvertible {
static func convertFromBooleanLiteral(value: Bool) -> Bool
}
protocol BooleanLiteralConvertible {
typealias BooleanLiteralType
class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}
в чем разница между функцией-членом, определенной как static func
и еще один, определенный как class func
? Просто ли это static
для статических функций, структур и перечислений, и class
для классов и протоколы? Есть ли другие различия, о которых следует знать? Каково обоснование наличия этого различия в самом синтаксисе?
7 ответов
это просто, что static для статических функций структур и перечислений и class для классов и протоколов?
это главное отличие. Некоторые другие различия заключаются в том, что функции класса динамически отправляются и могут быть переопределены подклассами.
протоколы используют ключевое слово class, но оно не исключает структуры из реализации протокола, они просто используют статические. Класс был выбран для протоколов, так что не должно было быть третье ключевое слово для представления static или class.
от Криса Латтнера на эту тему:
мы рассматривали унификацию синтаксиса (например, использование "type" в качестве ключевого слова), но на самом деле это не просто вещи. Ключевые слова "class" и "static" хороши для знакомства и довольно описательны (как только вы поймете, как работают методы+), и открывают дверь для потенциально добавления действительно статических методов в классы. Главная странность этой модели заключается в том, что протоколы чтобы выбрать ключевое слово (и мы выбрали "класс"), но в балансе это правильный компромисс.
и вот фрагмент, который показывает некоторые из поведения переопределения функций класса:
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
чтобы быть яснее, я приведу здесь пример,
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
это то же самое, что final class func
потому что это final
, мы не можем переопределить в подклассе, как показано ниже:
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"
}
}
Я сделал несколько экспериментов на игровой площадке и получил некоторые выводы.
как вы можете видеть, в случае class
использование class func
или static func
это просто вопрос привычки.
детская площадка пример с объяснением:
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."
чтобы объявить свойство переменной типа, отметьте объявление с помощью
static
декларации модификатор. Классы могут отмечать вычисляемые свойства типа с помощьюclass
вместо этого модификатор объявления позволяет подклассам переопределять реализацию суперкласса. Свойства типа обсуждаются в разделе свойства типа.Примечание
В объявлении класса ключевое словоstatic
имеет тот же эффект, что маркировка декларацию сclass
иfinal
декларации модификаторов.
источник: Свойства Переменной Типа Языка Программирования Swift
согласно Книге Swift 2.2, опубликованной apple:
" вы указываете методы типа, написав static
ключевое слово перед ключевым словом func метода. Классы также могут использовать class
ключевое слово чтобы позволить подклассам переопределять реализацию суперкласса, что метод."
Из Swift2.0, Apple говорит:
" всегда префикс типа требования свойства со статическим ключевым словом, когда вы определяете их в протоколе. Это правило относится, даже если требования к свойствам типа могут иметь префикс class или static ключевое слово при реализации классом:"
основное различие заключается в том, что структуры являются типами значений, а классы являются ссылочными типами.
когда вы делаете копию типа значения, он копирует все данные из вещи, которую вы копируете в новую переменную. Это 2 отдельные вещи, и изменение одного не влияет на другое
когда вы делаете копию ссылочного типа, новая переменная ссылается на то же место памяти, что и вещь, которую вы копируете. Это означает, что изменение одного изменит другое, так как они оба относятся к одному и тому же местоположению памяти