Multi-Line String Literals
01 何が問題だったのか
Swift には長らく、複数行にわたる文字列をそのまま書ける構文がありませんでした。XML や JSON のメッセージ、スクリプトのヘルプテキストなど、複数行の文字列を扱う場面は少なくありませんが、従来は次のように "..." による一行文字列を + で連結するか、明示的な改行文字 \n を埋め込む必要がありました。
let xml = "<?xml version=\"1.0\"?>\n" +
"<catalog>\n" +
" <book id=\"bk101\">\n" +
" <title>XML Developer's Guide</title>\n" +
" </book>\n" +
"</catalog>"
この書き方にはいくつもの不便があります。
"を文字列中で使うたびに\"とエスケープする必要があり、HTML/XML/JSON のように"が多く出現するテキストでは読みにくくなります。- 改行のたびに
\nを書くか、行ごとに+で連結する必要があります。 - 連結を多用すると、コンパイラの型推論に負荷がかかり、コンパイルが遅くなることもあります。
- 外部から貼り付けたテキストをそのまま使えず、必ず加工を強いられます。
複数行文字列リテラルは多くの言語で標準的に備わっている機能であり、Swift にも同様の仕組みを導入することが求められていました。
02 どのように解決されるのか
""" で囲む 複数行文字列リテラル(multi-line string literal) が導入されました。""" で始めて """ で閉じるあいだの行は、改行や " をエスケープせずにそのまま書くことができます。
let xml = """
<?xml version="1.0"?>
<catalog>
<book id="bk101" empty="">
<author>\(author)</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications with XML.</description>
</book>
</catalog>
"""
通常の文字列リテラルと同じように、\(...) による文字列補間も利用できます。
構文のルール
複数行文字列リテラルには次のルールがあります。
- 開始の
"""の直後には改行が必要で、その最初の改行はリテラルの内容には含まれません。 - 終了の
"""は独立した行に置きます。終了"""の前の改行もリテラルには含まれません。 - 終了
"""の前に置かれたインデント(空白文字列)が、各行の先頭から取り除かれます。これを インデントストリッピング(indentation stripping) と呼びます。
上の例では、終了 """ が4つのスペースでインデントされているため、各行の先頭の4スペースが取り除かれ、実際の文字列は <?xml version="1.0"?> から始まります。これにより、ソースコード上では周囲のコードに合わせて整形しつつ、実行時の文字列からは余分なインデントを取り除くことができます。
インデントの整合性
各行の先頭のインデントが、終了 """ の前のインデントと整合しない場合(たとえばスペースとタブが混在しているなど)は、コンパイラが警告を出します。意図しないインデントずれを早期に検知できます。
改行のエスケープ
行末に \ を置くと、その行の改行がリテラルに含まれなくなります。ソース上では複数行に分けて書きたいものの、結果としては一行の文字列にしたい場合に使えます。
let message = """
This is a long sentence that \
continues on the next line \
without an actual newline.
"""
// "This is a long sentence that continues on the next line without an actual newline."
使いどころ
貼り付けたテキストを加工せずにそのままコードに埋め込めるため、次のような用途で特に便利です。
- XML / JSON / HTML のテンプレート
- スクリプトの使い方メッセージやヘルプ表示
- SQL クエリや正規表現など、
"やバックスラッシュを含む文字列 - テストで用いる長い期待値文字列