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

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

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

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

2282閲覧

Kotlin の Null-Safety について

mosa

総合スコア218

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

1クリップ

投稿2017/09/09 01:32

編集2018/04/02 14:03

いつもありがとうございます。
Kotlin の Null-Safety について質問させてください。

Kotlin

1class C { 2 fun m() = println("hello") 3}

というクラスがあったとき、

###コード1

Kotlin

1var c: C? = null 2c = C() 3c.m()

これはコンパイルがとおります。ですが、

###コード2

Kotlin

1var c: C? = C() 2c.m()

これは Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type C? というコンパイルエラーとなります。
「コード1」がOKで、「コード2」がNGである理由を教えていただけますでしょうか。


###■追記補足

###コード3

これも通る。

Kotlin

1var c: C? = C() 2// c.m() // ←これは× 3c = C() 4c.m()

※タイトルを修正しました。

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

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

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

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

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

fuzzball

2017/09/11 04:51

valでも同じエラーが出ますね。なんだろう‥。
fuzzball

2017/09/11 05:25

ところで、質問のコードはスマートキャストと関係ないのでは?
mosa

2017/09/11 05:41

あああ、すみません。スマートキャストのことを調べているときに疑問に思ったことだったので混同していました。
mosa

2017/09/11 05:41

どのようなタイトルが適切なのでしょうか。。
mosa

2017/09/12 05:32

タイトルを「Kotlin の Null-Safety について」に変更しました
guest

回答1

0

ベストアンサー

調べてみましたが簡単に見つからなかったので、私の個人的な見解を述べてみたいと思います。
(シンタックスハイライトがうまくいかなかったのでjavaで言語指定しています。)

コード1

java

1var c: C? = null // cという変数は、Cのオプショナル型で定義し、メモリが確保され初期値はnullである。 2c = C() // c参照しているメモリにオプショナルではないCのインスタンスを代入する。 3c.m()

コード2

java

1var c: C? = C() // cという変数は、Cのオプショナル型で定義し、メモリが確保され初期値はCのインスタンスである。 2c.m()

違い

コード1:cという変数はnullを許容し、これにnon-nullな値を代入する。
コード2:cという変数はnullを許容し、初期値がnon-nullである。

1ではnullを情報として初期に持っている変数に対して、途中から値が代入され、それがnon-nullだったという場合です。
2ではnull許容の型で定義された変数のあくまで初期値がnon-nullであり、そのあとでnullを含めた変数として変数を扱う可能性が十分にあります。

と述べてきましたが、私自身確信を持てるものではありません。他にもご意見などありましたら、是非とも伺いたいなと思います!

投稿2017/09/09 07:54

hiramekun

総合スコア428

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

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

mosa

2017/09/11 04:38

ご回答ありがとうございます。もう少し他の回答も待ってみたいと思います。 どのような回答があればベストアンサーでどのような回答があれば終了なのかの落とし所を考えていませんでした。明確な答えがあるものなのでしょうか。。。
hiramekun

2017/09/11 14:26

そうですね、、 ただ明確に、初期化と代入というのは別のことをしているので、あながち見当違いではないかもしれないと思っています。
mosa

2017/09/12 00:28

追加の質問で恐縮ですが、コード1と2で、c.m() の直前では c の内部状態が異なる、ということでしょうか。(コード2はコンパイルできていないので内部状態も何もないですが。。。)
fuzzball

2017/09/12 00:43

println(c.javaClass) しようとすると、コード2の方は、 Type parameter bound for T in val <T : Any> T.javaClass: Class<T> is not satisfied: inferred type C? is not a subtype of Any というエラーが出ます。 私ではこのエラーを読み解けませんが、何か違うのは確かですね。
hiramekun

2017/09/12 01:04

fuzzballさま エラーメッセージについてですが、これはcというインスタンスがオプショナル型であるので、エラーが出ていますね。kotlinのAny型はnullを含めていないので、Anyにnullを入れるとエラーが発生します。 mosaさま 内部状態という言葉の意味によりますね。 正確にいうと、kotlinが変数を異なるものとして扱うと言っていいと思います。 なぜ異なるものとして扱うのかは、やはり初期化時のクラスの扱いと、代入時の変数の扱いの違いからくるのではないかと考えていますが、確信は持てないのでどこかで情報を見つけたらシェアしますね。
fuzzball

2017/09/12 01:21

代入時、代入されたものによってオプショナル型になったり非オプショナル型になったりしているということなのでしょうか?
mosa

2017/09/12 05:32

補足を追記しました。
hiramekun

2017/09/13 01:11 編集

fuzzballさま いえ、kotlinのメソッド、`javaClass`は、オプショナル型のインスタンスからよびだすことはできません。 オプショナル型のインスタンスからメソッドを呼ぼうとしているためのエラーですね
fuzzball

2017/09/13 01:25

ん‥?あー、「変数の型」ではなく「インスタンスの型」ということですかね。そもそも「変数の型」なんて言わないのかな‥。いまいち理解が浅くてすみません。
mosa

2018/04/02 14:08

すごい今更ですが、補足を書き直し、コード3を追加しました。コード3の挙動も含めて改めて見直してみたらhiramekunさんの回答がしっくりきました。hiramekunさん、fuzzballさんありがとうございました。 引き続き何か情報がありましたらご教示いただけますと幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問