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

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

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

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

Q&A

解決済

1回答

1609閲覧

Swiftの定数名の命名方法について

AKTO

総合スコア11

Swift

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

3グッド

1クリップ

投稿2018/08/25 10:19

編集2018/08/29 07:13

Swiftの変数(→定数)名の命名方法についての質問です。

let a: Int? = 123 if let a: Int = 123 { print(a) } print(a)

上記を実行したところ、結果は
123
Optional(123)
となりました。

つまり、SwiftではInt?型の変数(→定数)aがあっても、if-letのところでInt型のaを新しく宣言してもよく、ifの中ではInt型のaが優先的に使われるということでしょうか?

おそらく勘違いしていると思われるので、理解力のない私にも分かるアンサーをお待ちしてます...。

p.s.
Optional(123)となるのがInt型の変数(→定数)aのスケール(→スコープ)のため、ということだけは分かります。

xAxis👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

この質問見た瞬間おもしろいと思ったので調べてみました。

まずはコードから

swift

1 2let value: Int = 150 3 4class Shadowing { 5 6 let value: Int? = 100 7 8 init() { 9 let value = value //エラー 10 if let value = value { 11 print(value) // 12 13 print(self.value) 14 } 15 print(value) 16 } 17 18} 19

上記の例だとInt?型の定数valueとif-let構文中の定数valueの名前が同じですよね。このように同じ名前のものを使う事をシャドーイングと言うそうです(今初めて名前を知りました。シャドーイングを言いたいだけちゃうんかと言うツッコミは受け付けません)。

そして質問内容の

Int?型の変数aがあっても、if-letのところでInt型のaを新しく宣言してもよく

これはYesです。ただし質問に書かれてるInt型のaもInt?型のaも変数ではなく定数です。変数はvarです。

ifの中ではInt型のaが優先的に使われるということでしょうか?

これは優先的というよりもif-let構文内で定数aと言えばInt型のaの事を指します。self.aとするとInt?型のaを指します。この辺はスコープの問題とも絡んできますね。

なので勘違いはほとんどなく理解に問題ないんじゃないでしょうか。

(追記)

tyobigorouさんのコメントを受けて修正します。

Swiftはオプショナルバインディング中でのシャドーイングが可能になっています。これは例外として出来ることで通常シャドーイングは出来ないようになっていそうです。もしかしたらやり方があるかもしれませんが自分の調べた結果ではオプショナルバインディング中のみでした。SwiftはHaskellに影響を受けていると聞いたことがあり、そのHaskellでもシャドーイングが可能です。そしてHaskellではシャドーイングが出来る範囲もSwiftよりも広いようです。
そしてそのシャドーイングの効果ですが代入する値を特定スコープ内で使えなくする、という効果です。だから上記の例でメンバ定数であるvalueはif-let構文のブロック中では直接呼び出せなくなっていてvalueを呼び出すとif-let構文の条件で宣言された定数valueが呼び出される、ということのようです。

余談

swift

1class Shadowing { 2 3 let value: Int? = 100 4 5 init() { 6 if let value = value { 7 print(value) // 100 8 let value = 150 9 print(value) //150 10 print(self.value) // Optional(100) 11 } 12 print(value) //Optional(100) 13 } 14 15}

何故かこれが許される・・・。

投稿2018/08/25 11:50

編集2018/08/29 05:50
xAxis

総合スコア1349

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

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

xAxis

2018/08/25 11:58

コメント外に1つ追記です。このシャドーイング、正直何をやってるコードなのかぱっと見分かりづらいのであまり書かない方がよさげに思います。
AKTO

2018/08/25 12:16 編集

たしかに変数ではなく全部letなので定数ですね、誤植でした。 おそらくxAxisさんは調べているうちにQiitaの記事にたどり着いたんでしょうね。 私は調べているうちにあるQiitaの記事にたどり着き、シャドーイングについて読んだのですが、いまいち理解と確信を得られませんでした。 シャドーイングについてですが、ifの中の無印のaということは、たしかにself.aとは違いそうですね。 ところで、「ifの中ではInt型のaが優先的に使われるということでしょうか?」と書きましたが、すいません、私としては「Int?型よりもInt型が優先されるか?」というつもりではなく、「if-letで宣言したaが優先的に使われるか?」というつもりでした。 xAxisさんは「これは優先的というよりもif-let構文内で定数aと言えばInt型のaの事を指します。」とおっしゃってるので、たぶん、「if-letで宣言したaが優先的に使われる」というのはあってるんでしょうかね...? お忙しいところお答えいただきありがとうございました。ベストアンサーにさせていただきます。
退会済みユーザー

退会済みユーザー

2018/08/25 13:42 編集

調べてみて、初めて知りました。 自分の場合は↓のような感じかと思いますが、 let a: Int? = 123 if let a = a { print(a) // => 123 print(self.a) // => Optional(123) } print(a) // => Optional(123) if letでのオプショナルバインディング時に新たに定数名を考えなくてよくて、スコープ内ではself.aとaで使い分けもできるというのは、合理的でメリットがありそうに感じます。 有益な情報をありがとうございました。
xAxis

2018/08/25 14:35 編集

>>AKTOさん > 調べているうちにQiitaの記事にたどり着いた その通りでQiitaの記事にもたどり着きました。他にも別のQiitaの記事がいくつかと個人サイトがいくつか、あとはどこかの会社のサイトを読んだような気がします(すいません正直なところすでに忘れかけてます)。そして皆さん割と「シャドーイング初めて知ったぜ!」的なノリの記事だったので自分も少々悪ふざけをしてしまいましたw > 「Int?型よりもInt型が優先されるか?」というつもりではなく、「if-letで宣言したaが優先的に使われるか?」 読み返してみたのですが自分の回答の表現では「Int?型よりもInt型が優先されるか?」と言う受け取り方も可能でしたね。完全に誤算でした。すいません。 この問いにもストレートにYesと言っていいと思います。ただもっと厳密に言うならば「優先順位はなく」、「if-letで宣言したaが使われる」と表現した方が良いんじゃないかなと思います。 こちらこそ今回のように新たな知識を得る機会に恵まれありがとうございました!そして面白かったです! >>tyobigorouさん > if letでのオプショナルバインディング時に新たに定数名を考えなくてよくて 最初上のコード書いた時ぱっと見何やってんのか分かんないなーとか思ってたんですけども、コードの命名を上手に行っておけばわざわざ新たに定数名を考えなくて良いってのはメリットですね。思いつきませんでした。オプショナルバインディングするとき「ここの定数名どうすんだよ・・・」みたいなパターンってありますもんね。勉強になりました!
MasakiHori

2018/08/25 15:49

失敗しないinit内では使えませんけど、 guard let value = value else { return } とすればそれ以降はguardで宣言されたvalue(Int型)が使われることになります。 何度もアンラップする必要がなくなります。 分かりづらいきらいもあるにはありますが。
xAxis

2018/08/26 00:17

>>MasakiHoriさん > guard let value = value else { return } とすればそれ以降はguardで宣言されたvalue(Int型)が使われることになります。 これ、言われてみれば確かにその通りなのですが書いていただかなければ自分では気付けませんでした。勉強になります!
fuzzball

2018/08/27 01:14 編集

if let の変数名 https://www.toyship.org/archives/2229 私はSwiftを使い始めてすぐの頃にこの記事を読んだので、基本的に同じ名前を使うようにしています。
xAxis

2018/08/27 05:30

>>fuzzballさん 記事拝見しました。 回答した段階では名前の重複はまずいんじゃないかと思っていました。理由は記事にものってる通りのものです。 ですがtyobigorouさんのコメントで名前重複するのもありかもしれないという風に思いここ数日このネタをずっと考えていたのですが、 fuzzballさん貼ってくださった記事で重複させた方がよい、と自分の中でも結論付ける事が出来ました。 いつも様々な事を教えていただいてありがとうございます!今回も勉強になりました!!
AKTO

2018/08/28 18:13

>>xAxisさん 「if-letで宣言したaが使われると表現した方正しい。なぜなら、そうゆう文法だから。」とした方が厳密になりそうですね。 ただ私としては、これはこうゆうもんだから、と覚えるのが納得いかなかったもんで、優先という単語を使って自分を満足させました。 すいません、僕の言葉遊びにつきあわせてしまいました。 >>MasakiHoriさん guard let value = value else { return }でそれ以降アンラップする必要がないのは、value?なのにvalue!みたいだと感じました。 使い所があるかもしれませんね。
xAxis

2018/08/29 05:50 編集

>>AKTOさん > これはこうゆうもんだから、と覚えるのが納得いかなかったもんで、 これは自分もよく分かります。なので微力ではありますが追記で解説をしてみました。もし分からなければまたおっしゃってください。 追記 >>tyobigorouさんのコメントを受けて修正を行いました。
退会済みユーザー

退会済みユーザー

2018/08/29 05:12 編集

この場合の名称重複は、定数aが生きているうちに再度定数aを宣言できるといった類のものなので、 非オプショナル化時のみ認められた例外なんじゃないでしょうか? 例外とされた理由は、非オプショナル化するだけだから、使い勝手がいいから、古い言語からそうだから?(あれ、objective-Cとかってoptionalないんだっけ?)、 まあ、例外を認めるのは、そのほうが合理的なんだと思います。(多分非合理な例外は認めてくれないだろうから。) オプショナルバインディングという目的からみても、if-let文のスコープの中は非オプショナルaが優先されるのが当然だと思われます。目的は安全にaに触るためですし、でなければif-let文なんて書く意味ないでしょうし。 なのでif-let/guard-let時は重複した名称を使用するほうが普通なんだと思います。 (僕は、if let b = a {} / guard let b = a else {return}という例文で学んだので、a = a なんて通らないと思いこんでいて、打ったこともありませんでした。アホですね…。 ) 論点がずれました。 aを優先するというより同じa(ただし非optional)ということではないでしょうか?
xAxis

2018/08/29 05:52 編集

>>tyobigorouさん > 非オプショナル化時のみ認められた例外なんじゃないでしょうか? 今も調べてたりしたのですが、自分が根本的に勘違いしていました。tyobigorouさんのおっしゃる通りでそれはシャードイングの効果ではないかと思います。そのシャドーイングの効果というのは代入する側の値を使えなくするという効果で、だからメンバ変数はそのままの名前では使えなくなるんじゃないのかなと思っています。 swiftはHaskellを結構取り込んでるとも聞きますし、Haskellでもシャドーイングはあるようです。また例外というのも多分その通りでswiftのオプショナルバインディングで限定されているように思われますが、Haskellにおけるシャドーイングはかなり融通が利くようです。 自分もオプショナルバインディング時には名前を変えて使っていましたよw今必死に書き換えていますw
退会済みユーザー

退会済みユーザー

2018/08/29 07:43 編集

余談についてなんですが、そこはスコープ内部なので許されるようです。 if-letでなくてif文でも通ると思います。
AKTO

2018/08/29 07:29

結論として、「オプショナルバインディング時のみ認められるシャドーイング、という特例」ということなんですね。 tyobigorouさんが言っている同じaというのがなんとなく理解できました。 確かに、じゃなきゃif-letなんてする必要ないですね。 初心者の私にとってまだ微妙な感じではありますが、見やすくするために同じ名前を使ってもいい、ということだけは今後に活かせそうです。 余談についてですが、これはSwiftがまだまだ改善されていくことの証明ですかね...。
xAxis

2018/08/29 09:13

>>tyobigorouさん これが許される理由結構考えてるんですけども考えても考えても全然分からないです。 なのでまず各定数valueのスコープから考えてるんですけどもそれでもどう捉えたら良いものか五里霧中な今日この頃。 if文内で定数valueが宣言出来るのは分かるんですけども、if-let内で定数valueを宣言出来るということはif-letのブロック内にある定数valueと条件で宣言されてる定数valueのスコープは違いますよね?何か特殊なスコープにあるとか・・・? >>AKTOさん > 結論として、「オプショナルバインディング時のみ認められるシャドーイング、という特例」ということなんですね。 今度こそこれで大丈夫だと思います。回答に時間がかかってしまって申し訳ないです。 この余談全然分からないんですよね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問