首页 文章

Swift中static func和class func有什么区别?

提问于
浏览
262

我可以在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 回答

  • 10

    简单地说静态是针对结构和枚举的静态函数,还是类和类的类?

    这是主要的区别 . 其他一些区别是类函数是动态调度的,可以被子类覆盖 .

    协议使用class关键字,但它不排除实现协议的结构,它们只是使用static . 为协议选择了类,因此不必使用第三个关键字来表示静态或类 .

    来自Chris Lattner关于这个主题:

    我们考虑统一语法(例如使用“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
    
  • -6

    为了更清楚,我在这里举个例子,

    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 funcfinal 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"
      }
    }
    
  • 8

    我在操场上做了一些实验并得出了一些结论 .

    TL;DR
    enter image description here

    正如您所看到的,在 class 的情况下,使用 class funcstatic func 只是一个习惯问题 .

    Playground example with explanation:

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

    要声明类型变量属性,请使用静态声明修饰符标记声明 . 类可以使用类声明修饰符标记类型计算属性,以允许子类覆盖超类的实现 . 类型属性在类型属性中讨论 . 注意在类声明中,关键字static与使用类和最终声明修饰符标记声明具有相同的效果 .

    资料来源:The Swift Programming Language - Type Variable Properties

  • 168

    根据苹果发布的Swift 2.2 Book:

    “通过在方法的func关键字之前写入 static 关键字来指示类型方法 . 类也可以使用 class 关键字 to allow subclasses to override the superclass’s implementation of that method . “

  • 145

    从Swift2.0开始,Apple说:

    “在协议中定义类型属性要求时,始终使用static关键字作为前缀类型属性要求 . 即使类型属性要求在类实现时可以使用类或静态关键字作为前缀,此规则也适用:”

  • 49

    主要区别在于结构是值类型,类是引用类型 .

    复制值类型时,它会将您要复制的事物中的所有数据复制到新变量中 . 它们是两个独立的东西,改变一个不会影响另一个

    制作引用类型的副本时,新变量引用与要复制的内容相同的内存位置 . 这意味着更改一个将更改另一个,因为它们都指向相同的内存位置

相关问题