Swift.RangeはCodableである、ではencodeフォーマットは?

Swift.Range/ClosedRangeはCodable

Swiftは範囲を表現する型にRange/ClosedRangeを用意してる。

CountableRange CountableClosedRange というそれぞれのwhere条件を持つtypealiasもあるが、ここでは同じものだと思ってほしい。

Range/ClosedRangeBoundEncodable/Decodable である時、Range/ClosedRangeEncodable/Decodable にconformする。
つまり、Codableである。

では、Range/ClosedRangeJSONEncoderJSONDecoder に通すと、どんなフォーマットになるだろう?
試してみましょう。
※encode/decodeはカスタマイズしないものとする

環境

  • Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
  • Xcode Version 14.2 (14C18)
    • Playground

Range

Range は半開区間 (左閉右開) である。

RangeをJSONファイルで保存する

import Foundation

let fileManager = FileManager.default
let encoder = JSONEncoder()

let path = NSTemporaryDirectory()
print(path)

do {
    struct Content: Codable {
        var name: String
        var value: Range<Int>
    }

    let contents: [Content] = [
        .init(name: "0..<9", value: 0..<9),
        .init(name: "10..<13", value: 10..<13),
        .init(name: "14..<39", value: 14..<39),
    ]

    do {
        let data = try encoder.encode(contents)
        let json = try JSONSerialization
            .jsonObject(with: data, options: .fragmentsAllowed)
        print(json)

        let location = URL(fileURLWithPath: path)
            .appending(path: "Range.json")
        try data.write(to: location)
    } catch {
        print(error)
    }
}

結果

[
    {
        "name":"0..<9",
        "value":[
            0,
            9
        ]
    },
    {
        "name":"10..<13",
        "value":[
            10,
            13
        ]
    },
    {
        "name":"14..<39",
        "value":[
            14,
            39
        ]
    }
]

ClosedRange

ClosedRange は閉区間である。

ClosedRangeをJSONファイルで保存する

import Foundation

let fileManager = FileManager.default
let encoder = JSONEncoder()

let path = NSTemporaryDirectory()
print(path)

do {
    struct Content: Codable {
        var name: String
        var value: ClosedRange<Int>
    }

    let contents: [Content] =  [
        .init(name: "0...9", value: 0...9),
        .init(name: "10...13", value: 10...13),
        .init(name: "14...39", value: 14...39),
    ]

    do {
        let data = try encoder.encode(contents)
        let json = try JSONSerialization
            .jsonObject(with: data, options: .fragmentsAllowed)
        print(json)

        let location = URL(fileURLWithPath: path)
            .appending(path: "ClosedRange.json")
        try data.write(to: location)
    } catch {
        print(error)
    }
}

結果

[
    {
        "name":"0...9",
        "value":[
            0,
            9
        ]
    },
    {
        "name":"10...13",
        "value":[
            10,
            13
        ]
    },
    {
        "name":"14...39",
        "value":[
            14,
            39
        ]
    }
]

つまり...

Range/ClosedRange をencodeした結果は [a, b] となり、フォーマットは共通である。
encode/decodeにご注意ください。

追記

2022/12/15 23:55

RangeCodable にconformさせるプロポーザルを教えてもらいました。
Add Codable conformance to Range types