https://youtu.be/PzkrYzjK4yY
今回も引き続き オプショナルバインディング
の話題を見て行きます。これまでにだいぶ話した分野ではありますけれど、The Swift Programming Language の方でも丁寧に解説がされているので、それに則って基礎的なところの総浚いをして行きますね。よろしくお願いします。
それと今回は、ゆめみ社外の人への一般公募はなかったようなので、基本的に社内メンバーのみでの開催になりそうです。
————————————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #157
00:00 開始 00:58 StringProtocol についてのおさらい 02:21 StringProtocol を簡単に扱えるようになる 03:13 最新の Swift を Web の Playground から試す 04:49 some を用いたジェネリクスの書き方 06:37 String と Substring で区別なく使えるメソッドを作る 09:15 StringProtocol を試しに使ってみるのをオススメ 10:47 引数で some StringProtocol を使う例 11:47 Swift の文字列リテラルと文字リテラルの区別 12:49 some StringProtocol に値を渡す 14:34 文字リテラルの存在に気づくのが難しい 15:27 Swift で Character を扱うには? 18:28 Character の定義から特徴を窺う 21:00 ExpressibleByStringLiteral に対応させるとき 23:50 Character を扱う機会があまりない 25:53 単一引用符による文字表現 27:35 文字列リテラルでエスケープシーケンスを回避する 29:04 文字列と文字を明確に分けなかったのが気になる 31:09 単一リテラルの文字列リテラル 33:45 クロージング —————————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #157
では始めましょう。今日も引き続きオプショナルバインディングの話をしていきます。先に、前回の続きとしてお伝えしたいことがありますので、それを見てからオプショナルバインディングのおさらいをしていきます。前回話した内容がスライドにまとめられているので、それを見ながら進めていきましょう。
まず、前回脱線して「Stringプロトコルは便利だよ」という話をしましたよね。String
を使用して部分文字列を取得する際、Substring
型はパフォーマンスを考慮して最適化されている型です。これを維持して活用することで、全体的なパフォーマンス向上に繋がります。そこで、String
やSubstring
に対して型変換を伴わずに使える関数を用意すると、良いAPIデザインができるというお話をしました。
具体的なコード例を見てみましょう。このコードは、任意の型(String
プロトコルに準拠した型)を受け取り、それを活用するものです。この一般的な書き方が、間もなく開催されるAppleの新しいイベントで発表される新しいSwiftのリリースで、より書きやすくなる見込みです。これにより、Stringプロトコル
がより使いやすくなります。
例えば、次のような関数を考えます。
func countOf<S: StringProtocol>(letter: Character, in string: S) -> Int {
return string.filter { $0 == letter }.count
}
この関数は、String
やSubstring
型に対してStringProtocol
準拠型を受け取り、その中で指定された文字が何回登場するかを数えるものです。新しいSwiftでは、以下のようにさらに簡潔に書けるようになります。
func countOf(letter: Character, in string: some StringProtocol) -> Int {
return string.filter { $0 == letter }.count
}
このように書くことで、書き方が簡潔になり、より読みやすくなります。これは、文字列を操作するAPIを設計する際に非常に便利です。例えば、文字列の長さを返す関数や、特定の文字の数を数える関数などが考えられます。その他にも、上記の方法は様々なメソッドに対して適用可能です。
また、APIデザインガイドラインに則って、機能をメソッドとして関連する主体に搭載することが重要です。例えば、文字列のプロパティを拡張する場合、StringProtocol
に対して次のように拡張を追加します。
extension StringProtocol {
func countOf(letter: Character) -> Int {
return self.filter { $0 == letter }.count
}
}
これにより、String
やSubstring
で直接countOf(letter:)
メソッドを使うことができます。このようにして、APIデザインが整然とし、直感的に利用できるようになります。
このような取り組みを通じて、効率的で使いやすいコードを書くことができます。ぜひ、新しいSwiftの機能を試してみてください。 こういった書き方をすると、String
やSubstring
のどちらでも使えるメソッドが定義できます。要は、Substring
を取った場合でも、それをString
に変換せずに簡単に機能を呼び出して、最後にString
に整える(または変換して返す)ことができるようになります。このようにStringProtocol
を活用することを意識すると良いと思います。
String
プロトコルを使うべきか、String
を使うべきかという判断は難しいのですが、一度使ってみると感覚がつかめるかもしれません。試しにStringProtocol
をどこで使うかを意識すると、視野が広がるでしょう。
また、例としてStringProtocol
を使用することで、count
やfilter
などの一般的なメソッドも使えるようになります。したがって、StringProtocol
に準拠した型であれば多くのメソッドが利用可能になります。このような活用方法を覚えておくと良いでしょう。
他にも、文字列リテラルに関して、Swiftでは特定の1文字を扱うためのシングルクォートやダブルクォートなどの区別がないため、1文字のときのみキャラクターリテラルとして扱われます。他の言語ではシングルクォートでキャラクターリテラル、ダブルクォートで文字列リテラルという区別が用意されていますが、Swiftにはこのような区別がありません。
以上、具体的な例を紹介しましたが、StringProtocol
を活用すると、例えば文字列データの中で特定の文字をカウントするときに非常に効果的です。ぜひ、今回学んだStringProtocol
を活用してみてください。試してみることで、その便利さが実感できると思います。 業務コードにいきなりこれを使用しても、それほど困ることはないでしょう。最終的には、良い感じのコードになるのではないかと期待しています。現状、既にマジック付近で使用している場合は特に問題はありませんが、理解していることを確認しておくと、コードを書くのが楽しくなるのではないかと思います。 文字列リテラルとして扱う場合、それが文字列として解釈されます。明確なメッセージが出ない場合もあるため、注意が必要です。例えば、Character
は Expressible by
プロトコルに準拠していますが、どこで定義されているかを確認するために検索するとよいかもしれません。
また、Character
には UnicodeScalar
というプロトコルが存在し、それに準拠する形で定義されています。現状、Character
型は実際のところ、内部的に UnicodeScalarLiteral
のリテラルから変換され、さらに高次のレベルでは ExtendedGraphemeClusterLiteral
にも準拠しています。
かつて、Expressible by String Literal
に準拠させる際には、いくつかのイニシャライザが必要でした。例えば、次のようなコードです。
struct MyValue: ExpressibleByStringLiteral {
var value: String
init(stringLiteral: String) {
self.value = stringLiteral
}
}
let value: MyValue = "abc"
このように、文字列リテラルとして扱うためには、init(stringLiteral:)
を実装する必要がありました。同様に、UnicodeScalarLiteral
についても同様のイニシャライザが要求されました。
まとめると、リテラルは StringLiteral
、ExtendedGraphemeClusterLiteral
、そして UnicodeScalarLiteral
として扱われますが、最終的にはすべて String
型にまとめられて利用されます。しかし内部的には、それぞれ異なる扱いがされていることを理解しておくとよいでしょう。
プログラミングをしていると、文字列から Character
を取り出すことはあるものの、直接 Character
を操作することは少ないです。そのため、String
と Character
の間の変換や扱いには注意が必要です。
シングルクオーテーションとダブルクオーテーションの使い分けについても触れました。例えば、JavaScript や Ruby ではどちらの表記も可能ですが、使用シーンによっては統一感を持つことが推奨されます。個人の好みやプロジェクトのスタイルガイドに従って選択しているようです。 あの時にシングルクォーテーションを使っていなかったので、ダブルクォーテーションをちゃんとエスケープする必要がありました。エスケープ処理というのはよくある話ですが、これは便利だと思っていました。そして、逆のこともできます。ダブルクォーテーションをエスケープして、中身をシングルクォーテーションで囲むというのがそれです。最近だと、シャープを使うことでエスケープを避けられるようになりました。
例えば、文字列の解釈をエスケープしたくない場合は、シャープ付きのダブルクォーテーションを使えばいいという説明がなされました。この分かりやすさ優先の言語設計はよくできていると感じます。C言語のように文字列と文字を明確に分ける場合、ダブルクォーテーションは完全に文字列として使わないので、違ったアプローチが必要になります。
特にSwiftではシングルクォーテーションがないため、文字の扱いが少し複雑に感じられるかもしれませんが、シャープ付きのダブルクォーテーションの使用がその解決策となります。また、Swiftではシャープを使うことでエスケープ処理を避けることが可能となり、効率的なコードを書くことができます。
Javascriptのようにシングルクォーテーションとダブルクォーテーションが同じ動作をする言語もありますが、R言語ではシングルクォーテーションでは変数展開ができず、ダブルクォーテーションでは変数展開が可能です。これらの違いが混乱を招きますが、Swiftではシングルクォーテーションは存在せず、ダブルクォーテーションのみが使用されます。そのため、文字列の取り扱いは非常にシンプルです。
長らく混乱しがちなポイントについての理解が深まりました。本日はストリング周りの話をしましたが、次回はオプショナルバインディングについての話に戻りますので、お楽しみにしてください。どうぞよろしくお願いします。
お疲れ様でした。ありがとうございました。