# 拡張(Extensions)

最終更新日: 2022/8/13\
原文: <https://docs.swift.org/swift-book/LanguageGuide/Extensions.html>

既存の型に機能を追加する。

\_拡張機能\_は、既存のクラス、構造体、列挙型、またはプロトコル型に新しい機能を追加します。これは、(\_遡及モデリング\_と呼ばれる)元のソースコードにアクセスできない型を拡張することもできます。拡張機能は、Objective-C のカテゴリに似ています。(ただし、Objective-C のカテゴリとは異なり、Swift の拡張機能には名前がありません)

拡張機能は次のことができます。

* 計算インスタンスプロパティと計算型プロパティを追加する
* インスタンスメソッドと型メソッドを定義する
* 新しいイニシャライザを提供する
* サブスクリプトを定義する
* 新しくネスト型を定義する
* 既存の型をプロトコルに準拠させる

Swift では、プロトコルを拡張してその要件の実装を提供したり、準拠する型が利用できる機能を追加することもできます。詳細については、[Protocol Extensions(プロトコル Extension)](/the-swift-programming-language-jp/language-guide/protocols.md#protocol-extensions)を参照ください。

> NOTE\
> 拡張機能は型に新しい機能を追加できますが、既存の機能をオーバーライドすることはできません。

## 拡張機能の構文(Extension Syntax)

`extension` キーワードを使用して拡張機能を宣言します:

```swift
extension SomeType {
    // SomeType に新しい機能を追加します
}
```

拡張機能は、既存の型を拡張して、1 つ以上のプロトコルに準拠することができます。プロトコルへの準拠を追加するには、クラスまたは構造体の場合と同じ方法でプロトコル名を記述します。

```swift
extension SomeType: SomeProtocol, AnotherProtocol {
    // protocol の要件をここで実装します
}
```

この方法でプロトコル準拠を追加する方法は、[Adding Protocol Conformance with an Extension(拡張機能を使用したプロトコル準拠の追加)](/the-swift-programming-language-jp/language-guide/protocols.md#adding-protocol-conformance-with-an-extension)で説明されています。

拡張機能は、[Extending a Generic Type(ジェネリック型の拡張)](/the-swift-programming-language-jp/language-guide/generics.md#extending-a-generic-type)で説明されているように、既存のジェネリック型を拡張するためにも使用できます。ジェネリック型を拡張して、条件付きで機能を追加することもできます([Extensions with a Generic Where Clause(ジェネリックな Where 句を使用した拡張機能](/the-swift-programming-language-jp/language-guide/generics.md#extensions-with-a-generic-where-clause)を参照ください)。

> NOTE\
> 拡張機能を定義して既存の型に新しい機能を追加すると、拡張機能が定義される前に作成されたものであっても、その型の既存の全てのインスタンスで新しい機能を使用できます。

## 計算プロパティ(Computed Properties)

拡張機能は、計算インスタンスプロパティと計算型プロパティを既存の型に追加できます。この例では、5 つの計算インスタンスプロパティを Swift の `Double` 型に追加して、距離単位を使用するための基本的な機能を提供します。

```swift
extension Double {
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("1 インチは \(oneInch) メートル")
// 1 インチは 0.0254 メートル
let threeFeet = 3.ft
print("3 フィートは \(threeFeet) メートル")
// 3 フィートは 0.914399970739201 メートル
```

これらの計算プロパティは、`Double` の値を特定の長さの単位と見なしています。計算プロパティとして実装されていますが、ドット構文(`.`)を使用して浮動小数点リテラルの後に追加して使用できます。

この例では、`Double` の値 `1.0` が「1 メートル」を表しているため、計算プロパティ `m` は `self` を返します。式 `1.m` は、`Double` の値 `1.0` を計算していると見なされます。

他の単位では、メートルで測定された値として表現するために何らかの変換が必要です。1 キロメートルは 1,000 メートルに等しいので、計算プロパティ `km` は値に `1_000.00` を掛けてメートル単位の数値に変換します。同様に、メートルは 3.28084 フィート、に等しいので、 計算プロパティ `ft` は、基になる `Double` の値を `3.28084` で除算して、フィートからメートルに変換します。

これらのプロパティは読み取り専用計算プロパティのため、簡潔にするために `get` キーワードなしになっています。戻り値は `Double` 型で、`Double` が使用できるところでは、計算に使用することができます：

```swift
let aMarathon = 42.km + 195.m
print("マラソンは \(aMarathon) メートルです")
// マラソンは 42195.0 メートルです
```

> NOTE\
> 拡張機能は新しい計算プロパティを追加できますが、格納プロパティを追加したり、既存のプロパティにプロパティオブザーバを追加したりすることはできません。

## イニシャライザ(Initializers)

拡張機能は、既存の型に新しいイニシャライザを追加できます。他の型を拡張して、独自のカスタム型を初期化パラメータとして受け入れたり、型の元の実装の一部として含まれていなかった追加の初期化オプションを提供したりできます。

拡張機能は、新しい convenience イニシャライザをクラスに追加できますが、新しい指定イニシャライザまたはデイニシャライザを追加することはできません。指定イニシャライザとデイニシャライザは、常に元のクラス実装によって提供される必要があります。

拡張機能を使用して、カスタムイニシャライザを定義しない値型に全ての格納プロパティのデフォルト値を提供するイニシャライザを追加する場合は、拡張機能のイニシャライザ内からデフォルトイニシャライザとメンバワイズイニシャライザを呼び出すことができます。[Initializer Delegation for Value Types(値型のイニシャライザの委譲)](/the-swift-programming-language-jp/language-guide/initialization.md#initializer-delegation-for-value-types)で説明されているように、値型の元の実装の一部としてイニシャライザを作成した場合は、これに当てはまりません。

別のモジュールで宣言された構造体にイニシャライザを追加する場合、新しいイニシャライザは、定義モジュールからイニシャライザを呼び出されるまで、`self` にアクセスできません。

下記の例では、幾何学的な長方形を表す独自の `Rect` 構造体を定義しています。この例では、`Size` と `Point` という 2 つの補助的な構造体も定義されており、どちらも全てのプロパティにデフォルト値 `0.0` を提供します:

```swift
struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
}
```

`Rect` 構造体はその全てのプロパティにデフォルト値を提供しているため、[Default Initializers(デフォルトイニシャライザ)](/the-swift-programming-language-jp/language-guide/initialization.md#default-initializers)で説明されているように、デフォルトイニシャライザとメンバワイズイニシャライザを自動的に生成します。これらのイニシャライザを使用して、新しい `Rect` インスタンスを作成できます:

```swift
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
   size: Size(width: 5.0, height: 5.0))
```

`Rect` 構造体を拡張して、特定の中心点とサイズを取る追加のイニシャライザを提供できます:

```swift
extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}
```

この新しいイニシャライザは、提供された `center` と `size` の値に基づいて適切な原点を計算することから始まります。次に、イニシャライザは、構造体が自動で生成するメンバワイズイニシャライザ `init(origin:size:)` を呼び出します。これは、適切なプロパティに新しい原点とサイズの値を格納します:

```swift
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))
// centerRect の origin は (2.5, 2.5) で size は (3.0, 3.0) です
```

> NOTE\
> 拡張機能で新しいイニシャライザを提供する場合でも、イニシャライザの完了前に完全に初期化が完了していなければなりません。

## メソッド(Methods)

拡張機能は、新しいインスタンスメソッドと型メソッドを既存の型に追加できます。次の例では、`repetitions` という新しいインスタンスメソッドを `Int` 型に追加しています:

```swift
extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}
```

`repetitions(task:)` メソッドは、`() -> Void` 型の単一のパラメータを受け取ります。これは、パラメータがなく、値を返さない関数を示しています。

`repetitions(task:)` メソッドを呼び出して、任意の回数のタスクを繰り返し実行できます:

```swift
3.repetitions {
    print("こんにちは!")
}
// こんにちは!
// こんにちは!
// こんにちは!
```

### mutatingインスタンスメソッド(Mutating Instance Methods)

拡張機能を使用して追加されたインスタンスメソッドは、インスタンス自体を変更することもできます。`self` またはそのプロパティを変更する構造体および列挙型メソッドは、元の実装のメソッドを変更するのと同じように、インスタンスメソッドを `mutating` としてマークする必要があります。

下記の例では、`Int` 型に元の値を二乗する `square` と呼ばれる新しい `mutating` メソッドを追加しています:

```swift
extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
// someInt は 9
```

## サブスクリプト(Subscripts)

拡張機能は、既存の型に新しいサブスクリプトを追加できます。この例では、`Int` 型に整数のサブスクリプトを追加します。この `subscript[n]` は、数値の右から `n` 桁の `10` 進数を返します。

* `123456789[0]` は `9` を返します
* `123456789[1]` は `8` を返します

…など:

```swift
extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]
// 5 を返します
746381295[1]
// 9 を返します
746381295[2]
// 2 を返します
746381295[8]
// 7 を返します
```

要求されたインデックスに対して十分な桁がない場合、サブスクリプトの実装は、番号の左側にゼロが埋め込まれているかのように、`0` を返します。

```swift
746381295[9]
// 0 を返します
0746381295[9]
```

## ネスト型(Nested Types)

拡張機能は、新しいネスト型を既存のクラス、構造体、および列挙型に追加できます:

```swift
extension Int {
    enum Kind {
        case negative, zero, positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .zero
        case let x where x > 0:
            return .positive
        default:
            return .negative
        }
    }
}
```

この例では、新しいネスト列挙型を `Int` に追加します。`Kind` と呼ばれるこの列挙型は、特定の整数が表す数の種類を表します。具体的には、数値が負か、ゼロか、正かを表します。

この例では、`kind` と呼ばれる新しい計算インスタンスプロパティも `Int` に追加しています。これは、その整数に対して適切な `Kind` の列挙ケースを返します。

ネスト列挙型は、任意の `Int` 値で使用できるようになりました:

```swift
func printIntegerKinds(_ numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .negative:
            print("- ", terminator: "")
        case .zero:
            print("0 ", terminator: "")
        case .positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
// "+ + - 0 - 0 + "
```

この関数 `printIntegerKinds(_:)` は、`Int` 値の入力配列を受け取り、それらの値を順番に繰り返します。配列内の各整数について、関数はその整数の `kind` 計算プロパティを検証し、適切な説明を出力します。

> NOTE\
> `number.kind` は `Int.Kind` 型なことがすでにわかっているため、`Int.Kind` の各ケースは、`Int.Kind.negative` ではなく `.negative` など、`switch` 文内では省略して記述できます。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://swift-programming-language-jp.gitbook.io/the-swift-programming-language-jp/language-guide/extensions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
