web-dev-qa-db-ja.com

Swiftにおけるstatic funcとclass funcの違いは何ですか?

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がクラスとプロトコル用であるということですか?他に知っておくべき違いはありますか?構文自体にこの区別がある理由は何ですか?

294

単にstaticが構造体と列挙型の静的関数のためのものであり、クラスとプロトコルのためのクラスのためだけのものですか?

それが主な違いです。その他の違いは、クラス関数は動的にディスパッチされ、サブクラスによってオーバーライドされる可能性があることです。

プロトコルはclassキーワードを使用しますが、プロトコルの実装から構造体を除外するのではなく、代わりにstaticを使用します。プロトコルにはクラスが選択されているので、静的またはクラスを表すための3番目のキーワードは必要ありません。

このトピックに関する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
196
Connor

より明確にするために、ここで例を挙げます。

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"
  }
}
192
Jake Lin

私は遊び場でいくつか実験をし、いくつかの結論を得ました。

TL; DRenter image description here

ご覧のとおり、classの場合、class funcまたはstatic funcの使用は単なる習慣の問題です。

説明付きの遊び場の例:

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."
64
Nhon Nguyen

型変数プロパティを宣言するには、宣言にstatic宣言修飾子を付けて宣言します。サブクラスがスーパークラスの実装をオーバーライドできるようにするために、クラスは代わりにclass宣言修飾子で型計算されたプロパティをマークすることができます。型プロパティについては、型プロパティで説明しています。

NOTE
クラス宣言において、キーワードstaticは、classおよびfinal宣言修飾子の両方で宣言をマークするのと同じ効果があります。

出典: Swiftプログラミング言語 - 型変数のプロパティ

51
NexD.

アップルが発行したSwift 2.2 Bookによると、

「メソッドのfuncキーワードの前にstaticキーワードを書くことで型メソッドを指定します。また、クラスはclassキーワードを使用して、サブクラスがそのメソッドのスーパークラスの実装をオーバーライドできるようにすることもできます

13
Milad Ghattavi

Swift2.0以降、Appleは次のように述べています。

「プロトコルで定義するときは、常にtypeキーワードの要件にstaticキーワードを付ける

10
Jacky