【1m+1m+2m 3本/黒】RAMPOW usb c ケーブル タイプc ケーブル QC3.0対応高速充電 データ転送USB2.0規格 iPhone 16/16e 充電ケーブル/iPhone 15 充電ケーブル Sony Xperia/Samsung/Asus Zenfone/Fujitsu Arrows/PS5コントローラー タイプc多機種対応 在宅勤務支援
¥999 (2025年4月26日 13:07 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)【2025正規MFi認証品】i-Phone 充電ケーブル ライトニングケーブル 純正品質【1M/2M 各2本】充電器 ケーブル 2.4A急速充電 USB 充電コード 高速データ転送 断線防止 高耐久 i-Phone 14/14 Pro/13/13 Pro/12/11/X/8/8plus/7/6/iPad 各種対応
¥898 (2025年4月26日 13:07 GMT +09:00 時点 - 詳細はこちら価格および発送可能時期は表示された日付/時刻の時点のものであり、変更される場合があります。本商品の購入においては、購入の時点で当該の Amazon サイトに表示されている価格および発送可能時期の情報が適用されます。)
Swiftには様々なLiteralがあります。
ここで大事なのが、Swiftにおいて「Literal」と「Literalから生成される値の型」は別の概念だということです。
SwiftにおいてLiteralはどんな型の値でも生成することができます。そのため、Literalの記述だけを見て「XX型だ」と言い切ることはできません。
例えばSwiftUI.Text
をStringLiteral
を用いて初期化するコードを考えてみます。
ここで、"Hello"
から結果的に生成される値の型はString
ではありません。LocalzedStringKey
です。
init(
_ key: LocalizedStringKey,
tableName: String? = nil,
bundle: Bundle? = nil,
comment: StaticString? = nil
)
このLocalizedStringKey
のようにLiteralから初期化可能な型を作るためには、型をLiteral Protocolに準拠させる必要があります。
例えばLocalizedStringKey
はExpressibleByStringInterpolation
に準拠しています。
例として、以下のようにIntegerLiteralからStringを初期化できるようにしてみます。
この時String
をExpressibleByIntegerLiteral
に準拠させる必要があります。
まず、ExpressibleByIntegerLiteral
の定義を見てみます。
public protocol ExpressibleByIntegerLiteral {
associatedtype IntegerLiteralType: _ExpressibleByBuiltinIntegerLiteral
init(integerLiteral value: IntegerLiteralType)
}
IntegerLiteralType
というassociatedTypeがあります。これはLiteralから変換する際の中間表現に使う型です。さらにこの中間表現には_ExpressibleByBuiltinIntegerLiteral
の制約があります。
究極的(直接的)にLiteralから型に変換するにはコンパイラ上で実装が必要なので、コンパイラ上に実装があり、Literalから直接変換できる型(=_ExpressibleByBuiltinIntegerLiteral
)の中間表現を一旦噛ます必要があるわけです。
(厳密にはコンパイラ上で実装があってLiteralから直接変換できるのはBuiltin.IntX
型とかで、IntとかはそのBuiltin.IntX
を内部表現として持つので、Literalから直接変換できる=_ExpressibleByBuiltinIntegerLiteral
、という構造。)
ExpressibleByIntegerLiteral
のケースだと(コメントにあるように)stdlibの整数型と浮動小数点型が_ExpressibleByBuiltinIntegerLiteral
に準拠しています。
実際に実装してみると以下のようになります。
extension String: @retroactive ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
self.init(describing: value)
}
}
let number: String = 10
print(number)
以上がLiteral Protocolの概要です。Literal/Literal Protocolは複数ありますが、どれも中間表現が必要な点と、準拠の流れは基本的には同じです。
Swift 6.1時点でのLiteral Protocol一覧を簡単にまとめます。(RegexLiteralはLiteral Protocolがないので除外)
参考元は CompilerProtocols.swift
ExpressibleByNilLiteral
定義
public protocol ExpressibleByNilLiteral: ~Copyable, ~Escapable {
@lifetime(immortal)
init(nilLiteral: ())
}
中間表現は固定で()
(Void
)
利用例
enum JSON {
case null
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
case .null: "null"
}
}
}
extension JSON: ExpressibleByNilLiteral {
init(nilLiteral: ()) {
self = .null
}
}
let value: JSON = nil
print(value)
ExpressibleByIntegerLiteral
定義
public protocol ExpressibleByIntegerLiteral {
associatedtype IntegerLiteralType: _ExpressibleByBuiltinIntegerLiteral
init(integerLiteral value: IntegerLiteralType)
}
中間表現は_ExpressibleByBuiltinIntegerLiteral
: stdlibの整数型と浮動小数点型
利用例
enum JSON {
case null
case int(Int)
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
...
case .int(let int): int.description
}
}
}
extension JSON: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
self = .int(value)
}
}
let value: JSON = 10
print(value)
ExpressibleByFloatLiteral
定義
public protocol ExpressibleByFloatLiteral {
associatedtype FloatLiteralType: _ExpressibleByBuiltinFloatLiteral
init(floatLiteral value: FloatLiteralType)
}
中間表現は_ExpressibleByBuiltinFloatLiteral
: stdlibの浮動小数点型Float
, Double
, Float80
利用例
enum JSON {
case null
case int(Int)
case double(Double)
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
...
case .double(let double): double.description
}
}
}
extension JSON: ExpressibleByFloatLiteral {
init(floatLiteral value: Double) {
self = .double(value)
}
}
let value: JSON = 10.0
print(value)
ExpressibleByBooleanLiteral
定義
public protocol ExpressibleByBooleanLiteral {
associatedtype BooleanLiteralType: _ExpressibleByBuiltinBooleanLiteral
init(booleanLiteral value: BooleanLiteralType)
}
中間表現はExpressibleByBooleanLiteral
: Boolだけ
利用例
enum JSON {
case null
case int(Int)
case double(Double)
case bool(Bool)
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
...
case .bool(let bool): bool.description
}
}
}
extension JSON: ExpressibleByBooleanLiteral {
init(booleanLiteral value: Bool) {
self = .bool(value)
}
}
let value: JSON = false
print(value)
ExpressibleByUnicodeScalarLiteral
UnicodeScalarLiteral
は1つのUnicode Scalar(コードポイント)のみで構成されるStringLiteralのこと。
"a"
"ab"
"🔴"
"🖐️"
"(1)"
UnicodeとSwiftのUnicode表現についてはTSPL-Unicode-Representations-of-Stringsら辺を参考
定義
public protocol ExpressibleByUnicodeScalarLiteral {
associatedtype UnicodeScalarLiteralType: _ExpressibleByBuiltinUnicodeScalarLiteral
init(unicodeScalarLiteral value: UnicodeScalarLiteralType)
}
中間表現は_ExpressibleByBuiltinUnicodeScalarLiteral
: Unicode.Scalar
, Character
, String
, StaticString
利用例
実用的な利用例が思いつかなかったので適当な実装
struct MyUnicodeScalar: ExpressibleByUnicodeScalarLiteral {
var value: UnicodeScalar
init(unicodeScalarLiteral value: UnicodeScalar) {
self.value = value
}
}
let a: MyUnicodeScalar = "a"
ExpressibleByExtendedGraphemeClusterLiteral
ExtendedGraphemeClusterLiteral
は1つのCharacter
で構成されるStringLiteral。
つまり実質ExpressibleByCharacterLiteral
。(Swift.Characterはextended grapheme clusterの表現であるため。)
"a"
"ab"
"🔴"
"🖐️"
"(1)"
なおExpressibleByExtendedGraphemeClusterLiteral
はExpressibleByUnicodeScalarLiteral
の子protocolである。
定義
public protocol ExpressibleByExtendedGraphemeClusterLiteral
: ExpressibleByUnicodeScalarLiteral {
associatedtype ExtendedGraphemeClusterLiteralType
: _ExpressibleByBuiltinExtendedGraphemeClusterLiteral
init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType)
}
中間表現は_ExpressibleByBuiltinExtendedGraphemeClusterLiteral
: Character
, String
, StaticString
。
利用例
実用的な利用例が思いつかなかったので適当な実装
struct MyChar {
var value: Character
}
extension MyChar: ExpressibleByExtendedGraphemeClusterLiteral {
init(extendedGraphemeClusterLiteral value: Character) {
self.value = value
}
}
let a: MyChar = "a"
let c: MyChar = "🔴"
let d: MyChar = "👨👨👧👧"
ExpressibleByStringLiteral
StringLiteral。複数文字も表現可能だが、文字列展開はまだできない。
"a"
"ab"
"🔴"
"🖐️"
"(1)"
"""
let a = 10
"""
#"(10)"#
#"""
let a = "(10)"
"""#
なおExpressibleByStringLiteral
はExpressibleByExtendedGraphemeClusterLiteral
の子protocolである。
定義
public protocol ExpressibleByStringLiteral
: ExpressibleByExtendedGraphemeClusterLiteral {
associatedtype StringLiteralType: _ExpressibleByBuiltinStringLiteral
init(stringLiteral value: StringLiteralType)
}
中間表現は_ExpressibleByBuiltinStringLiteral
: StringとStaticString。
利用例
enum JSON {
case null
case int(Int)
case double(Double)
case bool(Bool)
case string(String)
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
...
case .string(let string): """ + string + """
}
}
}
extension JSON: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
self = .string(value)
}
}
let json = "hoge"
print(json)
ExpressibleByStringInterpolation
文字列展開を含むStringLiteral。
"a"
"ab"
"🔴"
"🖐️"
"(1)"
なおExpressibleByStringInterpolation
はExpressibleByStringLiteral
の子protocolである。
定義
中間表現はStringInterpolationProtocol
。
この中間表現の目的は他のLiteral Protocolとは違う。(10)
のような文字列展開は関数呼び出しに静的変換されており、StringInterpolationProtocol
はその呼び出し先関数を定義するレイヤーである。
参考: SE-0228 Fix ExpressibleByStringInterpolation
デフォルトの実装としてDefaultStringInterpolation
が用意されている。
public protocol ExpressibleByStringInterpolation
: ExpressibleByStringLiteral {
associatedtype StringInterpolation: StringInterpolationProtocol
= DefaultStringInterpolation
where StringInterpolation.StringLiteralType == StringLiteralType
init(stringInterpolation: StringInterpolation)
}
public protocol StringInterpolationProtocol {
associatedtype StringLiteralType: _ExpressibleByBuiltinStringLiteral
init(literalCapacity: Int, interpolationCount: Int)
mutating func appendLiteral(_ literal: StringLiteralType)
}
利用例
extension JSON: ExpressibleByStringInterpolation {
init(stringInterpolation: DefaultStringInterpolation) {
self = .string(stringInterpolation.description)
}
}
let json: JSON = "(1)"
print(json)
また、DefaultStringInterpolation
にextensionでappendInterpolation
を追加するか、StringInterpolationProtocol
自体を自分で実装することで任意の文字列展開の挙動を実現できます。コレは記事冒頭で言及したSwiftUI.Text
にも利用されているテクニックです。
struct UnicodeScalarLog: ExpressibleByStringInterpolation, CustomStringConvertible {
var description: String
init(stringLiteral value: String) {
description = value
}
init(stringInterpolation: StringInterpolation) {
self.init(stringLiteral: stringInterpolation.storage)
}
}
extension UnicodeScalarLog {
struct StringInterpolation: StringInterpolationProtocol {
var storage: String = ""
init(literalCapacity: Int, interpolationCount: Int) {
let capacityPerInterpolation = 2
let initialCapacity = literalCapacity + interpolationCount * capacityPerInterpolation
storage.reserveCapacity(initialCapacity)
}
mutating func appendLiteral(_ literal: StringLiteralType) {
storage += literal
}
mutating func appendInterpolation(unicodeScalarOf value: String) {
let unicodeScalars = value.unicodeScalars.map {
"U+($0.value)"
}.joined(separator: " ")
appendLiteral(unicodeScalars)
}
}
}
func printUnicodeScalar(_ log: UnicodeScalarLog) {
print(log)
}
let hand = "🖐️"
print("🖐️ is (hand)")
printUnicodeScalar("🖐️ is (unicodeScalarOf: hand)")
ExpressibleByArrayLiteral
定義
public protocol ExpressibleByArrayLiteral {
associatedtype ArrayLiteralElement
init(arrayLiteral elements: ArrayLiteralElement...)
}
中間表現は固定で中間表現は固定で可変超引数。ArrayLiteralElementは要素を指定するためのassociated type。
利用例
enum JSON {
case null
case int(Int)
case double(Double)
case bool(Bool)
case string(String)
case array([JSON])
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
...
case .array(let array):
"[" + array.map(.description).joined(separator: ", ") + "]"
}
}
}
extension JSON: ExpressibleByArrayLiteral {
init(arrayLiteral elements: JSON...) {
self = .array(elements)
}
}
let json = [1, "10", nil]
print(json)
ExpressibleByDictionaryLiteral
定義
public protocol ExpressibleByDictionaryLiteral {
associatedtype Key
associatedtype Value
init(dictionaryLiteral elements: (Key, Value)...)
}
中間表現は固定でタプルの可変超引数。
利用例
enum JSON {
case null
case int(Int)
case double(Double)
case bool(Bool)
case string(String)
case array([JSON])
case object([String: JSON])
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
...
case .object(let object):
"{" + object.map { """ + $0 + "": " + $1.description }.joined(separator: ",") + "}"
}
}
}
extension JSON: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (String, JSON)...) {
self = .object(Dictionary(uniqueKeysWithValues: elements))
}
}
let value: JSON = [
"id": "123456",
"name": "taro"
]
print(value)
余談ですが今までの利用例の実装でJSON
型が完成しました
フルコード
enum JSON {
case null
case int(Int)
case double(Double)
case bool(Bool)
case string(String)
case array([JSON])
case object([String: JSON])
}
extension JSON: CustomStringConvertible {
var description: String {
switch self {
case .null: "null"
case .int(let int): int.description
case .double(let double): double.description
case .bool(let bool): bool.description
case .string(let string): """ + string + """
case .array(let array):
"[" + array.map(.description).joined(separator: ", ") + "]"
case .object(let object):
"{" + object.map { """ + $0 + "": " + $1.description }.joined(separator: ",") + "}"
}
}
}
extension JSON: ExpressibleByNilLiteral {
init(nilLiteral: ()) {
self = .null
}
}
extension JSON: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
self = .int(value)
}
}
extension JSON: ExpressibleByFloatLiteral {
init(floatLiteral value: Double) {
self = .double(value)
}
}
extension JSON: ExpressibleByBooleanLiteral {
init(booleanLiteral value: Bool) {
self = .bool(value)
}
}
extension JSON: ExpressibleByArrayLiteral {
init(arrayLiteral elements: JSON...) {
self = .array(elements)
}
}
extension JSON: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (String, JSON)...) {
self = .object(Dictionary(uniqueKeysWithValues: elements))
}
}
extension JSON: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
self = .string(value)
}
}
extension JSON: ExpressibleByStringInterpolation {
init(stringInterpolation: DefaultStringInterpolation) {
self = .string(stringInterpolation.description)
}
}
let value: JSON = [[
"id": 10,
"name": "hoge",
"price": 1000,
"user": nil
], [
"id": 11,
"name": "fuga",
"price": 1100,
"user": [
"id": "123456",
"name": "taro"
]
]]
print(value)
_ExpressibleByColorLiteral
Playground literalと呼ばれるXcode側にUIで対応のある特殊なliteral。
ソース上でみるとただの関数呼び出しのように見えるが、Xcode上だと特殊なUIで表示される。
#colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1)
これ
定義
public protocol _ExpressibleByColorLiteral {
init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float)
}
利用例
extension SIMD4Float>: @retroactive _ExpressibleByColorLiteral {
public init(_colorLiteralRed red: Float, green: Float, blue: Float, alpha: Float) {
self.init(red, green, blue, alpha)
}
}
let simd4: SIMD4Float> = #colorLiteral(red: 0.1215686277, green: 0.01176470611, blue: 0.4235294163, alpha: 1)
print(simd4)
_ExpressibleByImageLiteral
Playground literalの一つ。
#imageLiteral(resourceName: "hogehoge.png")
定義
public protocol _ExpressibleByImageLiteral {
init(imageLiteralResourceName path: String)
}
利用例
struct MyImage {
var path: String
}
extension MyImage: _ExpressibleByImageLiteral {
init(imageLiteralResourceName path: String) {
self.path = path
}
}
let image: MyImage = #imageLiteral(resourceName: "hogehoge.png")
print(image.path)
_ExpressibleByFileReferenceLiteral
Playground literalの一つ。
#fileLiteral(resourceName: "resource.txt")
定義
public protocol _ExpressibleByFileReferenceLiteral {
init(fileReferenceLiteralResourceName path: String)
}
利用例
struct MyFile {
var path: String
}
extension MyFile: _ExpressibleByFileReferenceLiteral {
init(fileReferenceLiteralResourceName path: String) {
self.path = path
}
}
let file: MyFile = #fileLiteral(resourceName: "resource.txt")