Sự khác biệt giữa func tĩnh và func lớp trong Swift là gì?


334

Tôi có thể thấy các định nghĩa này trong thư viện Swift:

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

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

Sự khác biệt giữa hàm thành viên được định nghĩa là static funcvà hàm khác được định nghĩa là class funcgì? Có phải nó chỉ đơn giản staticlà dành cho các hàm tĩnh của cấu trúc và enum, và classcho các lớp và giao thức? Có sự khác biệt nào khác mà người ta nên biết về? Lý do để có sự khác biệt này trong chính cú pháp là gì?


3
Không có sự khác biệt thực sự. Họ không thể sử dụng func lớp trong một cấu trúc tôi đoán, do đó func tĩnh. struct func sẽ là một ứng cử viên tốt. Đây là một chút sắc nét nếu bạn hỏi tôi nhưng tốt, đó là những từ.
fabrice truillot de chambrier

2
Câu hỏi tiền thưởng, sau đó: một cấu trúc có thể phù hợp với một giao thức xác định một class func? Với thông tin chúng ta có bây giờ, sự khác biệt này có vẻ khá vô dụng, phải không?
Jean-Philippe Pellet

3
vâng, bạn có thể Lạ phải không?
fabrice truillot de chambrier

7
phần chênh lệch áp đảo là bạn có thể ghi đè lên class funcs
Fattie

1
Để được xem xét:error: class methods are only allowed within classes; use 'static' to declare a static method
Gabriel Goncalves

Câu trả lời:


238

Có phải chỉ đơn giản là tĩnh dành cho các hàm tĩnh của cấu trúc và enum, và lớp cho các lớp và giao thức?

Đó là sự khác biệt chính. Một số khác biệt khác là các hàm lớp được gửi động và có thể bị ghi đè bởi các lớp con.

Các giao thức sử dụng từ khóa lớp, nhưng nó không loại trừ các cấu trúc thực hiện giao thức, chúng chỉ sử dụng tĩnh thay thế. Lớp được chọn cho các giao thức vì vậy sẽ không phải có từ khóa thứ ba để thể hiện tĩnh hoặc lớp.

Từ Chris Lattner về chủ đề này:

Chúng tôi đã xem xét việc thống nhất cú pháp (ví dụ: sử dụng "loại" làm từ khóa), nhưng thực tế đó không đơn giản là những thứ. Các từ khóa "class" và "static" rất tốt cho sự quen thuộc và khá mô tả (một khi bạn hiểu cách thức + phương thức hoạt động) và mở ra cơ hội để thêm các phương thức tĩnh thực sự vào các lớp. Điều kỳ lạ chính của mô hình này là các giao thức phải chọn một từ khóa (và chúng tôi đã chọn "lớp"), nhưng trên cân bằng, đó là sự đánh đổi đúng đắn.

Và đây là đoạn trích hiển thị một số hành vi ghi đè của các hàm lớp:

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, điểm rất quan trọng là các chức năng của lớp được gửi đi một cách linh hoạt! Nhưng bạn có thể cung cấp một ví dụ như vậy? Bạn sẽ phải viết tên lớp ở đâu đó, phải không? Vậy tại sao không tĩnh chọn việc thực hiện lớp đó?
Jean-Philippe Pellet

1
Một câu hỏi bổ sung khác: bạn đã nhận được trích dẫn từ đâu?
Jean-Philippe Pellet

sự hiểu biết của tôi là các hàm lớp hoạt động khá giống với các phương thức objc + dưới mui xe
Connor

1
Tôi có thể cung cấp một liên kết câu trả lời đơn giản hơn ở đây? stackoverflow.com/questions/29636633/ từ
allenlinli

1
@ Jean-PhilippePellet Trong ví dụ trên ... nếu bạn sử dụng static func myFunc()thay vì class func myFuncbạn sẽ gặp lỗi sau l: không thể ghi đè phương thức tĩnh . Tại sao? Bởi vì nó như thể nó được đánh dấu final. Để biết thêm thông tin. Xem câu trả lời của nextD bên dưới. x.dynamicTypeHiện tại cũng đã được thay thế bằngtype(of:x)
Mật ong

246

Để rõ ràng hơn, tôi làm một ví dụ ở đây,

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 giống như final class func

Bởi vì nó là final, chúng tôi không thể ghi đè nó trong lớp con như dưới đây:

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
bạn vô địch, câu trả lời tuyệt vời .. tôi đã tìm kiếm sự khác biệt này .. Jake !!
Abhimanyu Rathore

5
Hoàn hảo. Ấn tượng.
Mehul

5
Điều này nên được đánh dấu là câu trả lời chính xác. Gọn gàng và sạch sẽ!
abhinavroy23

1
Giải thích tốt nhất! Điều này dẫn tôi đến một nghi ngờ khác. Có bất kỳ lý do rõ ràng để sử dụng một 'lớp func' không? Ý tôi là nếu bạn chỉ sử dụng 'func' thì nó cũng có thể bị ghi đè theo cùng một cách, vậy sự khác biệt là gì?
Marcos Reboucas

1
@MarcosReboucas nếu tôi hiểu chính xác câu hỏi của bạn, class funckhác với bình thường funcmặc dù cả hai đều có thể bị ghi đè. Nhưng funclà cho một cá thể / đối tượng và class funccó thể được truy cập thông qua lớp nhưClassA.classFunc()
Jake Lin

78

Tôi đã làm một số thí nghiệm trong sân chơi và có một số kết luận.

TL; DR nhập mô tả hình ảnh ở đây

Như bạn có thể thấy, trong trường hợp class, việc sử dụng class funchoặc static funcchỉ là một câu hỏi về thói quen.

Ví dụ sân chơi với lời giải thích:

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
Các ví dụ của bạn không bao gồm trường hợp được đề cập là sự khác biệt chính trong một câu trả lời khác: gửi động các classhàm so với ràng buộc tĩnh của các hàm static.
Jean-Philippe Pellet

1
Giải thích tuyệt vời cho sự hiểu biết chức năng.
Yucel Bayram

33
Không quá sức class func?
Iulian Onofrei

9
Nếu bạn cố gắng ghi đè một phương thức tĩnh, bạn S GET NHẬN ĐƯỢC L ERI. Tuy nhiên, bạn có thể ghi đè một phương thức lớp. Xem câu trả lời được chấp nhận
Mật ong

8
class funclà quá mức. Tôi sẽ bỏ phiếu này nếu không; yêu nghiên cứu và ví dụ!
Ben Leggiero

52

Để khai báo một thuộc tính biến loại, đánh dấu khai báo bằng công cụ staticsửa đổi khai báo. Các lớp có thể đánh dấu các thuộc tính được tính toán bằng công cụ classsửa đổi khai báo thay vào đó để cho phép các lớp con ghi đè lên việc thực hiện của lớp cha. Thuộc tính loại được thảo luận trong Thuộc tính loại.

LƯU Ý
Trong một khai báo lớp, từ khóa staticcó tác dụng tương tự như đánh dấu khai báo bằng cả hai biến tố khai báo classfinalkhai báo.

Nguồn: Ngôn ngữ lập trình Swift - Thuộc tính biến loại


5
Câu hỏi là hỏi về 'func tĩnh' và 'class func'. Nó KHÔNG hỏi về Thuộc tính Loại. Vì vậy, điều này không trả lời câu hỏi - mặc dù điều quan trọng là phải hiểu ngữ cảnh của các từ khóa này liên quan đến các thuộc tính.
etayluz

Câu trả lời này chỉ đơn giản là trên câu hỏi sai, có lẽ nó đã được đăng ở đây một cách tình cờ?
Fattie

15

Theo Sách Swift 2.2 được xuất bản bởi apple:

Bạn chỉ ra các phương thức loại bằng cách viết statictừ khóa trước từ khóa func của phương thức. Các lớp cũng có thể sử dụng classtừ khóa để cho phép các lớp con ghi đè lên cách thực hiện của lớp cha của phương thức đó .


10

Từ Swift2.0, Apple nói:

"Luôn luôn yêu cầu thuộc tính loại tiền tố với từ khóa tĩnh khi bạn xác định chúng trong giao thức. Quy tắc này liên quan đến mặc dù các yêu cầu thuộc tính loại có thể được tiền tố với lớp hoặc từ khóa tĩnh khi được lớp thực hiện:"


4

Ví dụ này sẽ xóa mọi khía cạnh!

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.
 */

Đầu ra: Đầu ra tất cả các loại chức năng


-6

Đây được gọi là phương thức kiểu và được gọi với cú pháp dấu chấm, như phương thức thể hiện. Tuy nhiên, bạn gọi các phương thức loại trên loại, không phải trên một thể hiện của loại đó. Đây là cách bạn gọi một phương thức kiểu trên một lớp có tên là someClass:


1
class someClass {class func someTypeMethod () {// thực hiện phương thức kiểu vào đây}} someClass.someTypeMethod ()
Kumar Utsav

Điều này không trả lời câu hỏi nào cả. Ông hỏi sự khác biệt giữa staticclasstừ khóa.
Doug McBride
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.