【问题标题】:Difference between type method and type instance method, etc?类型方法和类型实例方法等之间的区别?
【发布时间】:2015-12-11 00:43:38
【问题描述】:

注意:我已经阅读了苹果文档并研究了一本 swift 书。

  1. 我对“类型实例方法”(如果存在,如果我错了,请纠正我)和类型方法之间的区别感到困惑?

  2. 类方法和实例方法的区别?

  3. 类型属性和实例属性之间的区别(如果存在,抱歉我对类型属性主题很困惑)?

  4. 最后,swift中是否存在类属性?

很抱歉给您带来了困惑:'(

【问题讨论】:

    标签: swift types properties


    【解决方案1】:

    在 Swift 中,类型命名类型复合类型命名类型包括结构枚举协议。除了用户定义的命名类型之外,Swift 还定义了许多命名类型,例如数组、字典和可选值。 (让我们暂时忽略复合类型,因为它与您的问题没有直接关系。)

    为了回答您的问题,假设我创建了一个名为 Circle 的用户定义类(这只是一个示例):

    class Circle {
    
        static let PI = 3.14
    
        var radius: Double
    
        init(radius: Double) {
            self.radius = radius
        }
    
        // Returns the area of this circle
        func area() {
            return PI * radius
        }
    
        // Ridiculous class method for demonstration purposes
        static func printTypeName() {
            println("Circle")
        }
    } 
    
    1. 我对“类型实例方法”之间的区别感到困惑 (如果存在,如果我错了,请纠正我)和类型方法?

    如前所述,类型指的是类、结构、枚举、协议和复合类型。在上面的示例中,我使用了一个名为 Circleclass 来定义一个 type

    如果我想构建 Circle 类的单个对象,那么我将创建一个 实例。例如:

    let myCircleInstance = Circle(radius: 4.5)
    let anotherCircleInstance = Circle(radius: 23.1)
    

    以上是Circle的对象或实例。现在我可以直接调用它们的实例方法。我的类中定义的实例方法area

    let areaOfMyCircleInstance = myCircleInstance.area()
    

    现在,类型方法是一种可以在类型直接调用的方法,而无需创建该类型的实例。 p>

    例如:

    Circle.printTypeName()
    

    请注意,func 之前有一个 static 限定符。这表明它直接与类型有关,而不是与该类型的实例有关。

    1. 类方法和实例方法的区别?

    参见上面的解释。

    1. 类型属性和实例属性之间的区别(如果这样 存在,抱歉我对类型属性主题很困惑)?

    这与您的问题中的解释类似 除了,它不是应用于方法,而是应用于类型的属性(即属性、变量)。

    在我的Circle 示例中,属性定义为:

    static let PI = 3.14
    var radius: Double
    

    属性PI是一个类型属性;可以通过类型直接访问

    Circle.PI
    

    属性radius是该类型的实例属性;它可以由该类型的实例访问。使用我们之前创建的变量:

    // I can do this; it will be 4.5
    myCircleInstance.radius
    
    // And this; it will be 23.1
    anotherCircleInstance.radius
    
    // But I CANNOT do this because radius is an instance property!
    Circle.radius
    
    1. 最后,swift 中是否存在类属性?

    绝对!阅读我对上述问题 3 的解释。我的示例中的PI 属性是类属性的示例。

    参考资料:

    【讨论】:

      【解决方案2】:

      不同之处在于为每个实例创建实例方法和属性。为整个类型创建类型方法和属性

      假设你有 struct Employee

      struct Employee {
        static var ID:Int = 0
        static var NAME:Int = 1
      
        static func getNameOfField(index:Int) -> String {
            var fieldName:String = ""
      
            if index == ID {
                fieldName = "Id"
            } else if index == NAME {
                fieldName = "Name"
            }
      
            return fieldName
        }
      
        var fields = [Int:String]()
      
        mutating func config(id:String, name:String) {
            fields[Employee.ID] = id
            fields[Employee.NAME] = name
        }
      
        func getField(index:Int) -> String {
            return fields[index]!
        }
      }
      
      var e0 = Employee()
      e0.config("1", name: "Mark")
      
      var e1 = Employee()
      e1.config("2", name: "John")
      
      print(e0.getField(Employee.NAME))               // prints "Mark"
      print(Employee.getNameOfField(Employee.ID))     // prints "Id"
      

      struct e0 和 e1 的每个实例都有属性字段。它为每个实例创建并存在于其中。存储在 fields 属性中的值对于每个实例都是不同的。这就是为什么它被称为“实例属性”

      每个实例也有方法getField。它是为每个实例创建的,并且在这种情况下,它可以访问实例的 var 字段的属性和方法。这就是为什么它被称为“实例方法”

      您通过引用实例(在我们的例子中为 e0 和 e1)来访问实例属性和方法

      ID 和 NAME 是类型属性或静态属性。它们只创建一次,并且对于每个实例和每个其他对象都具有相同的值。 您可以通过引用“类型”(在我们的例子中为结构)Employee.NAME 来访问类型属性

      类型方法类似于类型(结构、类、枚举)的全局函数。它们通常用于封装绑定到类型但可能不需要实例的功能。与示例中一样,类型方法 getNameOfField(index:Int) -> String 根据索引返回字段名称。要返回此信息,您不必创建 Employee 的实例

      类型是结构、类和枚举

      您使用关键字 static 定义类型方法和属性(这就是它们也称为静态方法和属性的原因)

      结构和枚举可以具有类型属性和类型方法。 类只能有类型方法。您可以创建类型属性,但它必须是计算的

      在类中,您可以使用 static 或 class 关键字定义类型方法。不同的是类方法可以被覆盖。

      【讨论】:

      • 好兄弟,非常感谢!但是变异的东西让我很困惑......那是什么?它有什么作用?
      • 结构实例是不可变的。一旦创建,您将无法更改实例。将方法定义为 mutating 允许它对实例进行更改
      【解决方案3】:

      whyceewhite - 非常感谢!你已经澄清了一些我无法理解的事情! 来到本页并在 Swift 3+ 上运行的小伙伴们,如果你想将代码付诸实践并看到静态运行,请看下面的代码。

      class Circle {
      
      static let PI = 3.14
      
      var radius: Double
      
      init(radius: Double) {
          self.radius = radius
      }
      
      // Returns the area of this circle
      func area() -> Double {
          return Double.pi * radius
      }
      
      // Ridiculous class method for demonstration purposes
      static func printTypeName() {
          print("Circle")
      }
      }
      

      然后开始尝试 Circle.printTypeName 或上面显示的示例!好东西!

      【讨论】:

        【解决方案4】:

        这都是关于范围的,它定义了在哪里以及如何使用函数的边界。只有在从类中初始化对象后才能使用方法。简单来说,要使用方法,必须先创建对象,方法属于对象。

        但是,如果您需要使用方法但不需要启动对象,例如全局设置(例如 CLLocationManager 中的 authorizationStatus() 函数,该怎么办?对于 GPS 坐标授权),然后您可以创建一个类型方法,只需引用 type 名称(NOT 对象名称),然后调用经典的 doc 函数。

        【讨论】:

          【解决方案5】:

          @PaulBart1 对@whyceewhite 示例的修复有点棘手,因为他将声明的 PI 替换为 Swift 已知的常量默认值。 我为 Swift 4 重写了这个示例,如下所示:

          class Circle {
          
          //static let PI = 3.14  -> error: static member 'PI' cannot be used on instance of type 'Circle'
              let PI: Double = 3.1415
              var radius: Double
          
              init (radius: Double) {
                  self.radius = radius
              }
          
              // Return the area of this Circle
              func area() -> Double {
                  return PI * radius
              }
          
              // Radius class method for demonstration purposes
              static func printTypeName() {
                  print("Circle")
              }
          
          }
          
          let myCircleInstance = Circle(radius: 4.5)
          let anotherCircleInstance = Circle(radius: 23.1)
          
          Circle.printTypeName()   // Circle
          print(myCircleInstance.area()) // 14.13675
          print(anotherCircleInstance.area()) // 72.56865
          
           //
          

          【讨论】:

            猜你喜欢
            • 2015-04-17
            • 2012-08-06
            • 2017-02-15
            • 2013-06-12
            • 1970-01-01
            • 2012-07-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多