Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

構造体を文字列としてみる

struct Hoge {
 let name:String
 let age:Int
}

extension String.StringInterpolation {
mutationg func appendInterpolation(_ value: User) {
  appendInterpolation("Hoge's name is \(value.name) and he name is \(value.age)")
 }
}

としておいて、

let hoge = Hoge(name:"poi", age:44)
print("Hoge deatil \(hoge)) /// ここでhogeを引数にとっていることがポイント

これはCustomStringConvertibleと同じである。

しかし、こんなこともできる・

引数を好きなだけとれるのだ

extension String.StringIterpolation {
mutating func appendInterpolation(_ number: Int, style:NumberFormatter.Style) {
 formatter.numberStyle = style
 if let result = formatter.string(from: number as NSNumber) {
  appendLiteral(result)
 }
}

これで $20とか、1st, 12thとかできる。

let number = Int.random(in:0...100)
let lucky = "lucky number this weeks os \(number, style: .spellOut)."
print(lucky)

appendLiteralは必要に応じて何度も呼べる。

extension String.StringInterpolation {
mutating func appendInterpolation(repeat str: string, _ count:Int) {
 for _ in 0..< count {
  appendLiteral(str)
  }
 }
}
print("say, \(repat: "hello!,", 3)

他のSwiftの機能と組み合わせて例えば配列がないときはデフォルト表示するなどできる。

extension String.StringInterpolation {
 mutating func appendInterpolation(_ value:[String], empty defaultValue:@autoclosure () -> String) {
  if value.count == 0
     appendLiteral(defaultValue())
  } else {
    appendLiteral(values.joined(separator:","))
  }
 }
}

let particle = ["fermion", "boson"]
print("List of particle: \(names, empty: "No one").")

@autoclosureを使うことで単純なあたいや、複雑な関数を呼び出しできる。

ExpressibleByStringLiteralやExpressibleByStringInterpolationなどと組み合わせることで
文字列補間で全体の型を作れるようになり、CustomStringConvertibleを通してその型をprintできるようにさえなった。

必要なことは
ExpressibleByStringLiteralとExpressibleByStringInterpolationに準拠することで必要ならCustomStringConvertibleにも準拠すること。
自分の型の中にネストしてStringInterpolation構造体を作りStringInterpolationProtocolに準拠させる。その初期化には期待する大まかなデータ量を入れる必要がある。また、appendLiteral() を実装する必要がある。appendInterpolation()もいる。
初期化も2ついる。

様々な共通エレメントからHTMLを構成する型を例につくろう。

struct HTMLComponent: ExpressibleByStringLiteral, ExpressibleByStringInterpolation, CustomStringConvertible { struct StringInterpolation: StringInterpolationProtocol { // start with an empty string var output = ""

    // allocate enough space to hold twice the amount of literal text
    init(literalCapacity: Int, interpolationCount: Int) {
        output.reserveCapacity(literalCapacity * 2)
    }

    // a hard-coded piece of text – just add it
    mutating func appendLiteral(_ literal: String) {
        print("Appending \(literal)")
        output.append(literal)
    }

    // a Twitter username – add it as a link
    mutating func appendInterpolation(twitter: String) {
        print("Appending \(twitter)")
        output.append("<a href=\"https://twitter/\(twitter)\">@\(twitter)</a>")
    }

    // an email address – add it using mailto
    mutating func appendInterpolation(email: String) {
        print("Appending \(email)")
        output.append("<a href=\"mailto:\(email)\">\(email)</a>")
    }
}

// the finished text for this whole component
let description: String

// create an instance from a literal string
init(stringLiteral value: String) {
    description = value
}

// create an instance from an interpolated string
init(stringInterpolation: StringInterpolation) {
    description = stringInterpolation.output
}

}




let text: HTMLComponent = "You should follow me on Twitter (twitter: "twostraws"), or you can email me at (email: "paul@hackingwithswift.com")." print(text) /// You should follow me on Twitter @twostraws, or you can email me at paul@hackingwithswift.com.

これでHTMLが吐き出されるが、他にも使い方がありそう。

参考文献

[https://github.com/twostraws/whats-new-in-swift-5-0:title]