В чем разница между функцией static func и class 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 для статических функций structs и enums и class для классов и протоколов? Есть ли другие различия, о которых нужно знать? В чем смысл такого различия в самом синтаксисе?

Ответ 1

Это просто, что static для статических функций структур и перечислений, и class для классов и протоколов?

Это главное отличие. Некоторые другие различия заключаются в том, что функции класса отправляются динамически и могут быть переопределены подклассами.

Протоколы используют ключевое слово 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

Ответ 2

Чтобы быть более ясным, я приведу пример здесь,

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"
  }
}

Ответ 3

Я провел несколько экспериментов на детской площадке и сделал некоторые выводы.

TL; DR введите описание изображения здесь

Как вы можете видеть, в случае 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 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 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."

Ответ 4

Чтобы объявить свойство переменной типа, отметьте объявление с помощью модификатора объявления static. Классы могут пометить тип вычисляемых свойств с помощью модификатора объявления class вместо этого, чтобы позволить подклассам переопределять реализацию суперкласса. Свойства типа обсуждаются в свойствах типа.

Примечание
  В объявлении класса ключевое слово static имеет тот же эффект, что и объявление объявления с помощью модификаторов декларации class и final.

Источник: Язык быстрого языка - Свойства переменной типа

Ответ 5

Согласно книге Swift 2.2, опубликованной яблоком:

"Вы указываете методы типа, набирая ключевое слово static до ключевого слова func методов. Классы также могут использовать ключевое слово class , чтобы позволить подклассам переопределять реализацию этого класса суперклассами."

Ответ 6

Из Swift2.0 Apple говорит:

"Всегда задавать свойства типа префикса с ключевым словом static при определении их в протоколе. Это правило относится даже к тому, что требования к свойствам типа могут быть префикс класса или статического ключевого слова при реализации класса:"

Ответ 7

Класс final не может использоваться как свойство store, в то время как static с ним в порядке.

Ответ 8

Это называется типом методов и вызывается с точечным синтаксисом, как методы экземпляра. Однако вы вызываете методы типа для типа, а не для экземпляра этого типа. Вот как вы вызываете метод типа для класса SomeClass:

Ответ 9

Основное отличие состоит в том, что структуры являются типами значений, а классы являются ссылочными типами.

Когда вы создаете копию типа значения, она копирует все данные из вещи, которую вы копируете в новую переменную. Они являются 2 отдельными вещами, и изменение одного не влияет на другое.

Когда вы создаете копию ссылочного типа, новая переменная относится к той же ячейке памяти, что и копируемая вещь. Это означает, что изменение одного изменит другое, поскольку оба они относятся к одному и тому же местоположению памяти