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

What is the difference between static func and class func in Swift?

我可以在Swift库中看到这些定义:

1
2
3
4
5
6
7
8
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用于类和协议吗?还有什么我们应该知道的区别吗?语法本身有这种区别的理由是什么?


Is it simply that static is for static functions of structs and enums, and class for classes and protocols?

这就是主要的区别。还有一些区别是类函数是动态调度的,可以被子类覆盖。

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

Chris Lattner关于这个话题:

We considered unifying the syntax (e.g. using"type" as the keyword), but that doesn't actually simply things. The keywords"class" and"static" are good for familiarity and are quite descriptive (once you understand how + methods work), and open the door for potentially adding truly static methods to classes. The primary weirdness of this model is that protocols have to pick a keyword (and we chose"class"), but on balance it is the right tradeoff.

下面是一个片段,展示了类函数的一些重写行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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


更清楚地说,我在这里举了一个例子,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,我们不能在下面的子类中覆盖它:

1
2
3
4
5
6
7
8
9
10
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"
  }
}


我在操场上做了一些实验,得出了一些结论。

DRenter image description here

如你所见,在class的情况下,使用class funcstatic func只是一个习惯问题。

带解释的操场示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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."


To declare a type variable property, mark the declaration with the static declaration modifier. Classes may mark type computed properties with the class declaration modifier instead to allow subclasses to override the superclass’s implementation. Type properties are discussed in Type Properties.

NOTE
In a class declaration, the keyword static has the same effect as marking the declaration with both the class and final declaration modifiers.

< /块引用>

来源:Swift编程语言-类型变量属性


根据苹果出版的Swift 2.2书:

"通过在方法的func关键字之前写入static关键字,可以指示类型方法。类也可以使用class关键字来允许子类重写超类对该方法的实现。"


从Swift2.0,苹果说:

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


这称为类型方法,并使用点语法(如实例方法)调用。但是,可以对该类型调用类型方法,而不是对该类型的实例调用类型方法。以下是如何在名为SomeClass的类上调用类型方法:


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

当您复制一个值类型时,它会将您要复制的对象中的所有数据复制到新变量中。它们是两个分开的东西,改变一个不会影响另一个。

复制引用类型时,新变量引用的内存位置与正在复制的内容相同。这意味着改变一个会改变另一个,因为它们都指向相同的内存位置。