質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

4回答

1981閲覧

構造体において、引数に()ではなく[]ブラケットを使用するケース

pegy

総合スコア245

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/09/04 03:43

編集2020/09/04 03:55

Swift

1struct Impression { 2 static subscript(i: Int) -> String { 3 let level = (i < 0) ? 0 : (i > 4 ? 4 : i) 4 return ["a","b","c","d","e"][level] 5 } 6} 7print(Impression[3]) //d

return["a","b","c","d","e"][level]とすること文法的な意味と動作がどうしても今持ち合わせている知識から理解することができません。

確かに例えば3がiそしてlevelに代入されて以下のようにreturnする場合にはdが返るのは理解できます。
return["a","b","c","d","e"][3]

しかし、そもそも仮引数に値を入れて初期化する場合には文法上以下の記法と理解しております。
Impression(3)またはImpression(Int: 3)

このように構造体等において、仮引数に代入する値を代入する場合struct()ではなくstruct[]とするのはこのようなケースが特別なのでしょうか?どのように使い分けるのか少し混乱してきてしまい、アドバイスを頂けると幸いです。

添え字付けというものがそういうものであるということであればそのように覚えます。

宜しくお願い申し上げます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

()はイニシャライザの呼び出し、[]はサブスクリプトの呼び出しです

しかし、そもそも仮引数に値を入れて初期化する場合には文法上以下の記法と理解しております。
Impression(3)またはImpression(Int: 3)

このように構造体等において、仮引数に代入する値を代入する場合struct()ではなくstruct[]とするのは

このあたりに誤解があるのではないかと思います。

このImpression構造体を、Impression(3)や、Impression(int: 3)として作成することはできません。引数が合致するイニシャライザ(他の言語ではコンストラクタとも呼びます)がないからです。

一方で、Impression[3]はできます。subscriptを定義してあるからです。Impression[3]Impression.subscript(3)と同じです。これはインスタンス化ではなく、(サブスクリプトというちょっと特殊なものですが)タイプメソッドの呼び出しにすぎません。

()はイニシャライザの呼び出しで、[]はサブスクリプトの呼び出しです。
サブスクリプトがそういうものである、というのはozwkさんの回答の通りです。

また、subscriptの中身の解釈についてはy_waiwaiさんの回答のとおりで、["a","b","c","d","e"]という配列の、添え字にsubscriptの引数を使っているだけです。ここでポイントなのはインスタンスの情報を一切使っていないという点です。タイプメソッドなので、インスタンスの情報にはアクセスできません。
Impression[3]は、3という数値をもったImpression構造体のインスタンスを作成しているのではないのです。

イニシャライザについて

Impression構造体をImpression(int: 3)として作成できるようにするには、イニシャライザを用意してあげる必要があります。

swift

1struct Impression { 2 var value: Int 3 init(int: Int) { 4 value = int 5 } 6}

あるいは、以下の様にプロパティを用意するだけでも良いです。

swift

1struct Impression { 2 var int: Int 3}

プロパティの定義だけでよいのは、Swiftが自動的にメンバワイズイニシャライザと呼ばれるイニシャライザを作ってくれるからです。つまり、以下のように書いたのと同じと解釈されているからで、イニシャライザがないのではありません。

swift

1struct Impression { 2 var int: Int 3 init(int: Int) { 4 self.int = int 5 } 6}

(細かい話ですが、メンバワイズイニシャライザでは、引数名とプロパティ名が同じになるので、プロパティ名をintにしてあげないと、引数名をintにはできません。)

この状態でも、Impression(3)とするとエラーになります。
Impression(3)として使うには、別のイニシャライザが要ります。

swift

1struct Impression { 2 init(_ parameter: Int) { ... } 3}

引数名のないイニシャライザを定義してあげないと、引数名なしでインスタンス化させることはできません。

もし、Impression(3)でもImpression(int: 3)でも良いようにしたかったら、両方のイニシャライザを定義しなくてはなりません。

swift

1struct Impression { 2 var int: Int 3 init(_ int: Int) { 4 self.int = int 5 } 6 init(int: Int) { 7 self.int = int 8 } 9}

なお、メンバワイズイニシャライザは、他にイニシャライザ定義がないときだけ作成されるのでご注意ください。

※当初イニシャライザをコンストラクタと呼んでいましたがSwiftの言語仕様ではイニシャライザが正しいので、修正しました。

投稿2020/09/04 06:21

編集2020/09/06 00:56
eytyet

総合スコア803

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pegy

2020/09/05 13:07

詳細、ご解説いただきありがとうございます。 また、ご返信遅くなりましたことをお詫び申し上げます。 "()はコンストラクタの呼び出しで、[]はサブスクリプトの呼び出しです。" このご指摘が正に要点の様に思えます。構造体をその様に作ったのでそれに従って呼び出す方法が違うんですというところがまだ初心者の私にとっては雑かもしれないのですが、平易な考え方と思いました。 おそらく、構造体に何か引数の様なものを渡して、値を得る場合には必ずstruct()で呼び出すものという認識で勉強してきたため、戸惑ってしまったものだと思います。 ※ちなみに参考にしている書籍ではイニシャライザという表現でinit()の初期化メソッドを表現されていますが、ここで仰っていただいているコンストラクタと同義のものと解釈いたしました。そこの整理と理解に時間がかかっていたのですが、間違っていたら申し訳ございません。 また、コンストラクタ(イニシャライザ)についても詳細ご教示いただきありがとうございます。 "Impression[3]は、3という数値をもったImpression構造体のインスタンスを作成しているのではないのです。" このアドバイスも聞けて良かったです、思ったよりもsubscript自体が特殊な記法の様ですね。構造体のインスタンス化やイニシャライザ(コンストラクタ)の手続とは切り離して考えた方が良さそうです。 "Impression.subscript(3)" これだけが少し不思議でした、これはタイプメソッド に呼び出しなんですね。。。これは少し考えます。 お力添えに御礼申し上げます。
eytyet

2020/09/06 00:49

コメントをありがとうございます。コンストラクタとイニシャライザは同じという解釈で結構です。言語によって厳密な定義や用法がいろいろあります。 ご指摘をうけて調べたところ、Swiftではイニシャライザと呼んでいて、コンストラクタと言う用語は使っていませんでした。すいません。回答の方を修正しておきます。私の説明が配慮不足で、混乱を招いてしまい、申し訳ありませんでした。
pegy

2020/09/06 17:23

とんでもございません。一般的に同義であることは勉強になりました。 宜しくお願いします。
guest

0

おそらくstaticがあるために理解が阻害されているのだと思われます。

staticはそのclass/struct/enumに直接作用させることができる関数などに使用されます。
たとえば

swift

1struct A { 2 static func f() { 3 print("A") 4 } 5}

というものがあれば

swift

1print(A.f())

のようにAそのものに対して作用させるように使用します。

またsubscriptは特殊な関数でブラケット式[]で関数を実行するように使用します。
ArrayやDictionaryのsubscriptでご存じだと思います。

ご提示のコードはこのstaticsubscriptを複合させたものとなっています。
つまり、Impressionにたいして直接ブラケット式を作用させるsubscriptということです。

ですので、

swift

1print(A.f())

と同じように

swift

1print(Impression[3])

のように直接Impressionに対してブラケット式を使用します。


本件とは関係ありませんがご提示のコードは大変質の悪いコードです。
このレベルですと、余計なことに気を取られすぎてSwiftの学習の妨げとなると思われます。
このコードを提示してくるサイトや本はお勧めしません。

投稿2020/09/05 09:25

MasakiHori

総合スコア3391

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pegy

2020/09/05 13:21

コメントありがとうございます。 おそらくstaticはタイプメソッド なので var a = A() print(a.f())ではなくprint(A.f())のとするのが直接作用するという意味合いかと解釈いたしました。そこはなんとなく理解することができたのですが、なんで()ではなくてブラケット式で呼び出すの?というのがとても不思議だったのですが、他の方のコメントからも、これはそもそもコンストラクタ(イニシャライザ)ではないというを知ることができました。 ちなみに元々teratailで進められた、「詳解 Swift 第5版」という書籍で勉強を進めていてたのですが、確かに例示のコードが私には難しく、都度に躓いてしまいます。。 もちろん書籍自体は悪くないものの可能性はあるのですが、ある程度C系の言語をやったことをある人を前提として記載しているくだりもよくあるため、少なくとも私にはドンピシャであってはいなかったかもしれません。。といいつつ、アドバイスを胸に、もう少しこの書籍に食らいついてみようとは思っています!
guest

0

添え字付けというものがそういうものであるということであればそのように覚えます。

はい、そうです。

配列とか辞書に対してhoge[0]みたいに[]で要素にアクセスするあの機能を
自分で定義したクラスとか構造体でも使えるようにするために定義するのがsubscriptです。

なお、「みたいに」と書きましたがArraysubscript()がリファレンスにちゃんと載ってます。
subscript(Int) -> Element

投稿2020/09/04 04:43

編集2020/09/04 04:54
ozwk

総合スコア13553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pegy

2020/09/05 13:23

端的なご回答をいただきありがとうございます。 また、レファレンスについてもご提供ありがとうございます。まだ見ることに慣れないのですが、少し読みとてみようとおもいます。
guest

0

["a","b","c","d","e"]

配列、と考えれば理解できるんじゃないでしょうか

投稿2020/09/04 04:14

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pegy

2020/09/05 13:31

コメントをいただきありがとうございます。 直感的にはおっしゃる通りなのですが、なぜ一般的な構造体のタイプメソッド を呼び出すときにstruct()なのにstruct[]で違いがあるのかがわかりませんでした。。。例えば下記の様なタイプメソッド はstruct.add[2]とはせずにstruct.add(2)のはずですが、なぜブラケットなんだ〜〜〜と悩んでしまいました。 struct xxx { static func add (a: int) -> Int { return a + a } } ある意味subscriptはその様に定義していてその様なものだといえばその様に理解はできます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問