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

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

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

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Swift

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

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Q&A

解決済

2回答

1693閲覧

【Swift】変数宣言時、Returnで値を代入する式にも関わらず関数・クロージャー型ではない宣言の仕方について及び、インスタンスプロパティの使用タイミング

beginner_Jiro

総合スコア10

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Swift

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

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

0グッド

0クリップ

投稿2020/11/10 07:29

皆様、お世話になっております。

Swiftにて変数の宣言の仕方について基本的な構文で理解に苦しんでおります。どなたか下記点をご教授頂けますでしょうか。

疑問点とコード

●疑問1:Returnで値を返却するが「式」ではない変数の宣言

対象となっている変数宣言の記載が下記になります。

Swift

1var Message:String { 2 return "Hello" 3} 4Message

上記はReturn文で変数Message内の値を返しているように見受けられます。{}ブロックを使用していることからクロージャー式の省略した記載方法なのかと考えました。
いわゆる下記のような形です。

Swift

1var Message2 = {() -> String in 2 return "Hello" 3} 4Message2()

しかしそもそも前者の宣言では変数Message:Stringとして明示的にString型であることが証明されております。
変数を使用する時もMessage()とした場合

Swift

1//エラーコード 2Cannot call value of non-function type 'String'

上記のエラーで関数やクロージャー式でない旨が証明されました。

では前者のような書き方は「変数宣言時に{}ブロック内で返却された値を変数に代入する書き方」として単体で覚えてしまっても
問題ありませんでしょうか?こういった書き方に通称があるのかが気になって質問させていただきました。

●疑問2:構造体でインスタンスプロパティを内部で使用する際の記載

こちらも前述した疑問1に関連する内容になっております。
まず下記のコードについてです。

Swift

1struct letter { 2 var to:String 3// 下記はコンパイルエラー:Cannot use instance member 'to' within property initializer; property initializers run before 'self' is available 4 var message:String = "Hello(to)" 5 6// 下記は問題なくコンパイル可能 7 var message2:String { 8 return "Hello(to)" 9 } 10}

上記ではインスタンスプロパティであるtoを使用した際に違いが出ています。
普通に変数を代入している一回目のやり方と、疑問点1で記載した書き方は何が異なっているのか、
後者だとコンパイル可能になる理由がいまいちわかりません。
インスタンスプロパティであるtoはインスタンス化しないと使えないですよね。
{}ブロック内にtoを書き込むことでどういった変化が起き、なぜ同じ構造体のletterブロック内で使用できるようになるのかが
わかりません。

冗長な文章となってしまい申し訳ございません。
お手数ですが、どなたかご回答いただけますと幸いです。

以上になります。よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

回答1 Computed Propertyと呼ばれるものです。プロパティの一種なので、そのまま覚えても大丈夫です。

公式サイト

 計算ができるプロパティという認識でよいかと思います。

swift

1var name: Type { 2 // 読み出し 3 get { 4 return xxx 5 } 6 // 書き込み 7 set { 8 xxx = newValue 9 } 10}

などと書くことができます。読み込みのみでよいプロパティの場合は、set {}をまるごと削除し、get{}は中身だけ書くことができるので、疑問1と同じ形ができあがります。(公式サイトの中の、Read-Only Computed Propertiesを参照)

回答2 インスタンスを作成した時点で内容が決定しているかどうかがポイントです。
プロパティtoは、宣言があるだけなので、インスタンスを作った時点では中身がありません。そのため、

swift

1var message:String = "Hello(to)"

 も、その時点では中身を決定できないのです。一方、

swift

1var message2:String { 2 return "Hello(to)" 3}

は、プロパティへのアクセスがあったときに内容が決定します。そのため、エラーにはなりません。ただし、イニシャライザの中で、toの値を決定する前にmessage2をアクセスしようとするとエラーになります。

投稿2020/11/10 08:31

編集2020/11/10 08:35
AOKINAO

総合スコア268

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

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

beginner_Jiro

2020/11/12 05:17

AOKINAO様 お世話になっております。 ご回答いただきありがとうございます。 ゲッタ・セッタを用いるコンピューテッドプロパティの省略形だったとは…。 勉強したばかりだったのに…不甲斐ないです。 こちらについては、いまいちどコンピューテッドプロパティについて 頭に叩き直そうと思います。 ありがとうございます。 回答2に関しましては、別途ご回答いただけております方の記述も参考にさせていただきます。 ご回答いただきありがとうございました。助かりました。
guest

0

ベストアンサー

2についてAOKINAOさんの回答に補足させていただきます。

AOKINAOさんは中身がないからエラーになると書かれておりますがそうではありません。
初期化前から値が定まっており値が変化しない以下のようなプロパティでも初期化前にアクセスを行うとエラーが発生します。

swift

1struct A { 2 3 // 初期化時には値が確定しており且つletなのでそれが変化することもない 4 let a: Int = 1 5 6 // コンパイルエラー 7 let b = a * 2 8}

エラーの内容は

cannot use instance member 'a' within property initializer; property initializers run before 'self' is available

となっており、これはざっくりというと
「プロパティの初期化にプロパティaを使うことはできません。プロパティの初期化処理はselfが有効になる前に実行されます。」
となります。

先ほどのstructのコードでは省略されているのですがlet b = a * 2の部分はlet b = self.a * 2なのです。

このlet b = self.a * 2を見れば一目瞭然なのですが、
bの初期化にselfが使われています。
しかしselfを使うにはbが初期化されないといけません。
bを初期化するにはselfを使えるようにしなければいけません
.......ループ
のように処理が出来ない状態になってしまいます。

このような状態を避けるためSwiftではプロパティの初期化にほかのプロパティを利用することはできなくなっています。

ちなみにイニシャライザ内ではSwiftが特別な状態管理を行っているため利用不可のselfが表面上利用できているように見えます。

swift

1struct A { 2 let a = 1 3 let b: Int 4 5 init() { 6 7 // selfが利用可能になる前にselfを利用しているように見える 8 self.b = self.a * 2 9 } 10}

投稿2020/11/11 01:49

MasakiHori

総合スコア3391

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

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

beginner_Jiro

2020/11/16 06:07

エラー内容についてもわかりやすく解説していただきましたので ベストアンサーとさせていただきました。 他回答してくださった方も大変参考になりました。ありがとうございました。 また何か質問が発生しましたらその際は恐縮ですがご回答いただければと思います。 以上です。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問