Swift'te statik işlev ve sınıf işlevi arasında fark nedir?


334

Swift kütüphanesinde şu tanımları görebiliyorum:

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

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

Olarak tanımlanan bir üye işlevi static funcile başka bir olarak tanımlanan başka bir işlev arasındaki fark nedir class func? Basitçe static, yapıların ve numaraların statik işlevleri ve classsınıflar ve protokoller için mi? Bilmeniz gereken başka farklılıklar var mı? Sözdiziminde bu ayrımın olmasının mantığı nedir?


3
Gerçekten hiçbir fark yok. Sınıf işlevini sanırım bir yapıda kullanamadılar, dolayısıyla statik işlev. struct func iyi bir aday olurdu. Bana sorarsan biraz sinirli ama kelimeler bunlar.
fabrice truillot de chambrier

2
Bonus soru, o zaman: bir yapı, bir tanımlayan bir protokole uygun olabilir class funcmi? Şu an sahip olduğumuz bilgilerle bu ayrım işe yaramaz gibi görünüyor, değil mi?
Jean-Philippe Pellet

3
Evet yapabilirsin. Garip değil mi?
fabrice truillot de chambrier

7
ezici fark geçersiz kılabilirsiniz olduğunu class funcs
fattie

1
Dikkate alınması gereken:error: class methods are only allowed within classes; use 'static' to declare a static method
Gabriel Goncalves

Yanıtlar:


238

Statik, yapıların ve numaraların statik işlevleri ve sınıflar ve protokoller için sınıf için mi?

Temel fark budur. Diğer bazı farklar, sınıf işlevlerinin dinamik olarak gönderilmesidir ve alt sınıflar tarafından geçersiz kılınabilir.

Protokoller class anahtar sözcüğünü kullanır, ancak yapıları protokolü uygulamaktan dışlamaz, bunun yerine statik kullanırlar. Protokoller için sınıf seçildiğinden statik veya sınıfı temsil eden üçüncü bir anahtar kelime olması gerekmez.

Bu konuda Chris Lattner'den:

Sözdizimini birleştirmeyi düşündük (ör. Anahtar kelime olarak "type" kullanmak), ancak bu aslında basit bir şey değil. "Sınıf" ve "statik" anahtar kelimeleri, aşinalık açısından iyidir ve oldukça açıklayıcıdır (+ yöntemlerin nasıl çalıştığını anladıktan sonra) ve sınıflara gerçekten statik yöntemler eklemek için kapıyı açar. Bu modelin birincil garipliği, protokollerin bir anahtar kelime seçmesi gerektiğidir (ve "sınıf" ı seçtik), ancak dengede doğru denemedir.

Ve burada sınıf işlevlerinin bazı geçersiz kılma davranışlarını gösteren bir snippet:

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

4
Aha, sınıf fonksiyonlarının dinamik olarak gönderildiği çok önemli bir nokta! Ama böyle bir örnek verebilir misiniz? Sınıf adını bir yere yazmak zorundasın, değil mi? Öyleyse neden bu sınıfın uygulanmasını statik olarak seçmiyorsunuz?
Jean-Philippe Pellet

1
Bir başka tamamlayıcı soru: teklifi nereden aldınız?
Jean-Philippe Pellet

benim anlayışım sınıf fonksiyonları kaput altında objc + yöntemleri ile hemen hemen aynı çalışır
Connor

1
Burada daha basit bir cevap bağlantısı sağlayabilir miyim? stackoverflow.com/questions/29636633/…
allenlinli

1
@ Jean-PhilippePellet Yukarıdaki örnekte ... static func myFunc()bunun yerine kullanırsanız class func myFuncaşağıdaki hatayı alırsınız: l: statik yöntemi geçersiz kılamaz . Neden? Çünkü sanki onunla işaretlenmiş gibi final. Daha fazla bilgi için. Aşağıdaki nextD'nin cevabına bakın. Ayrıca x.dynamicTypeyerini aldıtype(of:x)
Honey

246

Daha açık olmak gerekirse, burada bir örnek vereceğim,

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 ile aynı final class func

Çünkü final, aşağıdaki gibi alt sınıfta geçersiz kılamayız:

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

18
şampiyon, harika cevap .. bu farkı arıyordum .. Jake !!
Abhimanyu Rathore

5
Mükemmel. Etkileyici.
Mehul

5
Bu doğru cevap olarak işaretlenmelidir. Düzgün ve Temiz!
abhinavroy23

1
En iyi açıklama! Bu beni başka bir şüpheye götürdü. 'Sınıf fonksiyonu' kullanmak için açık bir neden var mı? Yani sadece 'func' kullanırsanız, aynı şekilde geçersiz kılınabilir, o zaman fark nedir?
Marcos Reboucas

1
@MarcosReboucas Sorunuzu doğru anlarsam, her ikisi de geçersiz kılınabilmesine rağmen class funcnormalden farklıdır func. Ancak funcbir örnek / nesne içindir ve class funcaşağıdaki sınıftan erişilebilirClassA.classFunc()
Jake Lin

78

Oyun alanında bazı deneyler yaptım ve bazı sonuçlar elde ettim.

TL; DR resim açıklamasını buraya girin

Gördüğünüz gibi class, class funcveyastatic func alışkanlık sadece bir sorudur.

Açıklamalı oyun alanı örneği:

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

7
Örnekleriniz başka bir cevapta ana fark olarak belirtilen durumu kapsamaz: classfonksiyonların dinamik gönderilmesi ve bunların statik bağlanması static.
Jean-Philippe Pellet

1
Fonksiyonları anlamak için harika bir açıklama.
Yücel Bayram

34
Değil mi class funcgeçersiz kılınabilir?
Iulian Onofrei

9
Statik bir yöntemi geçersiz kılmaya çalışırsanız, HATA ALACAKSINIZ. Ancak yapabilirsiniz sınıf yöntemi geçersiz. Kabul edilen cevaba bakın
Honey

8
class funcgeçersiz kılınabilir. Bunu başka türlü oy verdim; araştırma ve örnek seviyorum!
Ben Leggiero

52

Bir type değişkeni özelliği bildirmek için, bildirimi staticbildirim değiştiricisiyle işaretleyin. Sınıflar, classalt sınıfların üst sınıfın uygulanmasını geçersiz kılmalarına izin vermek için tür hesaplanan özellikleri bildirim değiştiricisiyle işaretleyebilir . Tür özellikleri, Tür Özellikleri'nde ele alınmıştır.

NOT
Bir sınıf bildiriminde, anahtar kelime static, bildirimi hem classve hem de finalbildirim değiştiricileri ile işaretlemekle aynı etkiye sahiptir .

Kaynak: Swift Programlama Dili - Tür Değişken Özellikleri


5
Soru 'statik fonk' ve 'sınıf fonk' hakkında soru sormaktır. Tür Özelliklerini sormuyor. Yani bu soruya cevap vermiyor - yine de bu anahtar kelimelerin özellikler açısından bağlamını anlamak önemlidir.
etayluz

Bu cevap sadece yanlış sorudur, belki de yanlışlıkla burada yayınlanmıştır?
Fattie

15

Apple tarafından yayınlanan Swift 2.2 Kitabına göre:

“Yazım yöntemlerini, staticanahtar kelimeyi yöntemin func anahtar sözcüğünden önce yazarak belirtirsiniz . Sınıflar ayrıca alt sınıfların üst sınıfın bu yöntemi uygulamasını geçersiz kılmasına izin vermek için classanahtar kelimeyi kullanabilir . ”


10

Swift2.0'dan Apple diyor ki:

"Protokolde tanımladığınızda tip özellik gereksinimlerine her zaman statik anahtar kelime ile ön ek uygulayın. Bu kural, bir sınıf tarafından uygulandığında type özellik gereksinimlerine sınıf veya statik anahtar kelime ile ön ek eklenebilse bile geçerlidir:"


5

Bu örnek her yönü temizleyecektir!

import UIKit

class Parent {
    final func finalFunc() -> String { // Final Function, cannot be redeclared.
        return "Parent Final Function."
    }

    static func staticFunc() -> String { // Static Function, can be redeclared.
        return "Parent Static Function."
    }

    func staticFunc() -> String { // Above function redeclared as Normal function.
        return "Parent Static Function, redeclared with same name but as non-static(normal) function."
    }

    class func classFunc() -> String { // Class Function, can be redeclared.
        return "Parent Class Function."
    }

    func classFunc() -> String { // Above function redeclared as Normal function.
        return "Parent Class Function, redeclared with same name but as non-class(normal) function."
    }

    func normalFunc() -> String { // Normal function, obviously cannot be redeclared.
        return "Parent Normal Function."
    }
}

class Child:Parent {

    // Final functions cannot be overridden.

    override func staticFunc() -> String { // This override form is of the redeclared version i.e: "func staticFunc()" so just like any other function of normal type, it can be overridden.
        return "Child Static Function redeclared and overridden, can simply be called Child Normal Function."
    }

    override class func classFunc() -> String { // Class function, can be overidden.
        return "Child Class Function."
    }

    override func classFunc() -> String { // This override form is of the redeclared version i.e: "func classFunc()" so just like any other function of normal type, it can be overridden.
        return "Child Class Function, redeclared and overridden, can simply be called Child Normal Function."
    }

    override func normalFunc() -> String { // Normal function, can be overridden.
        return "Child Normal Function."
    }
}

let parent = Parent()
let child = Child()

// Final
print("1. " + parent.finalFunc())   // 1. Can be called by object.
print("2. " + child.finalFunc())    // 2. Can be called by object, parent(final) function will be called.
// Parent.finalFunc()               // Cannot be called by class name directly.
// Child.finalFunc()                // Cannot be called by class name directly.

// Static
print("3. " + parent.staticFunc())  // 3. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("4. " + child.staticFunc())   // 4. Cannot be called by object, this is override form redeclared version (normal function).
print("5. " + Parent.staticFunc())  // 5. Can be called by class name directly.
print("6. " + Child.staticFunc())   // 6. Can be called by class name direcly, parent(static) function will be called.

// Class
print("7. " + parent.classFunc())   // 7. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("8. " + child.classFunc())    // 8. Cannot be called by object, this is override form redeclared version (normal function).
print("9. " + Parent.classFunc())   // 9. Can be called by class name directly.
print("10. " + Child.classFunc())   // 10. Can be called by class name direcly, child(class) function will be called.

// Normal
print("11. " + parent.normalFunc())  // 11. Can be called by object.
print("12. " + child.normalFunc())   // 12. Can be called by object, child(normal) function will be called.
// Parent.normalFunc()               // Cannot be called by class name directly.
// Child.normalFunc()                // Cannot be called by class name directly.

/*
 Notes:
 ___________________________________________________________________________
 |Types------Redeclare------Override------Call by object------Call by Class|
 |Final----------0--------------0---------------1------------------0-------|
 |Static---------1--------------0---------------0------------------1-------|
 |Class----------1--------------1---------------0------------------1-------|
 |Normal---------0--------------1---------------1------------------0-------|
 ---------------------------------------------------------------------------

 Final vs Normal function: Both are same but normal methods can be overridden.
 Static vs Class function: Both are same but class methods can be overridden.
 */

Çıktı: Tüm fonksiyon türlerini çıktılar


-6

Buna tür yöntemleri denir ve örnek yöntemleri gibi nokta sözdizimi ile çağrılır. Ancak, yazım yöntemlerini bu türün bir örneğinde değil, türde çağırırsınız. SomeClass adlı bir sınıfta bir type yöntemini şöyle çağırırsınız:


1
class SomeClass {class func someTypeMethod () {// tür yöntemi uygulaması buraya gidiyor}} SomeClass.someTypeMethod ()
Kumar Utsav

Bu soruya hiç cevap vermiyor. O arasındaki farkı sordu staticve classanahtar kelimeler.
Doug McBride
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.