Swiftのリテラルについて

インターン先でSwiftの言語仕様について学ぶ機会があり、その中でリテラルについて学んだので少し理解を深掘りたいと思っています。

リテラルについて

まず、この記事を書くにあたり、リテラルについて調べてみる事にしました。

リテラルは、シンタックスシュガーの一つです。

hoge := "abc"

これをみた時、hogeString型である事がわかります。

僕たち人間は、このhogeをStringだと見ただけでわかりますが、機械ではこれを判断出来ません。

しかし、リテラルを用いる事で、値からそれがどの型なのかを自動的に推測しています。

Swiftのリテラル

Swiftでも、Int, Double, String, Character, Unicode, Bool, Optional, Array, Dictionaryのリテラルを提供しています。

https://nshipster.com/swift-literals/

let a = "abc" //String
let b = 1 // Integer
let c = true // Boolean

Optionalは、someとnoneの2つのケースが用意されているenumです。

しかし、Optional型と宣言しておけば、nilと文字を与えるだけでOptional型と推測されます。

let d: Optional<String> = nil

ExpressibleByNilLiteral

これは、Optional型がExpressibleByNilLiteralを継承しているからです。

nilリテラル nilを使用して初期化できる型と書かれています。 https://developer.apple.com/documentation/swift/expressiblebynilliteral

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)

    public init(nilLiteral: ())
}

Optional以外で、ExpressibleByNilLiteralを使うことは非推奨で、SwiftではOptionalImplicitlyUnwrappedOptionalおよび`_OptionalNilComparisonType`にのみ使用されています。

応用で使ってみると以下のようになります

struct Nilable: ExpressibleByNilLiteral {
    init(nilLiteral: ()) {}
}

let a: Nilable = nil

Nilableかたで、nil型推論を使って宣言する事ができます。

少し応用したものを書いてみました

enum HogeHoge {
    case none
    case success(String)
    case failure
}

extension HogeHoge: ExpressibleByNilLiteral {
    public init(nilLiteral: ()) {
        self = .none
    }
}

extension HogeHoge: ExpressibleByStringLiteral {
    init(stringLiteral value: StringLiteralType) {
        if value.count >= 8 {
            self = .success(value)
        } else {
            self = .failure
        }
    }
}

let a: HogeHoge = nil
let b: HogeHoge = "1234"
let c: HogeHoge = "12345678"

print(a) // none
print(b) // failure
print(c) // success("12345678")

ExpressibleByStringLiteralExpressibleByNilLiteralを使う事で、Validation機能を持った型を作成しました。

このように、リテラルの種類は決めれらていますが、Protocolを使う事でいろんな型をコントロールする事ができます。

まとめ

当たり前のように型推論を使っていましたがなぜという所に立ち戻ると、今回のようなリテラルのようなProtocolを使って実装されている事がわかりました。