В чем разница между статическим и классовым функциями в Swift?

282

Я вижу эти определения в библиотеке 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 для классов и протоколов? Есть ли другие различия, о которых нужно знать? В чем смысл такого различия в самом синтаксисе?

  • 2
    На самом деле нет никакой разницы. Я думаю, они не могли использовать класс func в структуре, следовательно, статический func. struct func была бы хорошим кандидатом. Это немного раздражительно, если вы спросите меня, но это слова.
  • 2
    Бонусный вопрос: может ли структура соответствовать протоколу, который определяет class func ? С информацией, которой мы располагаем сейчас, это различие кажется довольно бесполезным, не так ли?
Показать ещё 3 комментария
Теги:
class
static

8 ответов

183
Лучший ответ

Это просто, что 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
  • 3
    Ага, очень важный момент, что функции класса динамически отправляются! Но не могли бы вы привести такой пример? Вы должны были бы написать имя класса где-нибудь, верно? Так почему бы не выбрать статически реализацию этого класса?
  • 1
    Еще один дополнительный вопрос: откуда вы взяли цитату?
Показать ещё 6 комментариев
149

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

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"
  }
}
  • 13
    ты чемпион, отличный ответ .. я искал эту разницу .. Джейк !!
  • 5
    Отлично. Впечатляет.
Показать ещё 2 комментария
64

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

TL; DR Изображение 1683

Как вы можете видеть, в случае 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."
  • 7
    Ваши примеры не охватывают случай, упомянутый в качестве основного отличия в другом ответе: динамическая диспетчеризация функций class и статическая привязка static функций.
  • 1
    Отличное объяснение для понимания функций.
Показать ещё 5 комментариев
52

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

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

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

  • 3
    Вопрос заключается в том, что такое «статическая функция» и «классовая функция». Это НЕ спрашивает о свойствах типа. Таким образом, это не отвечает на вопрос - хотя важно понимать контекст этих ключевых слов и в отношении свойств.
10

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

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

8

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

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

0

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

  • 1
    class SomeClass {class func someTypeMethod () {// здесь идет реализация метода типа}} SomeClass.someTypeMethod ()
-5

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

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

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

  • 3
    Это не по теме. Я спрашивал о разнице между class func и static func .
  • 3
    Не по теме, но независимо от образования
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню