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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

340閲覧

「プロを目指す人のためのRuby入門(第2版)」のP247~248にあるプログラムに関する質問

pg1965

総合スコア3

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2022/04/26 16:33

編集2022/04/26 16:35

「プロを目指す人のためのRuby入門(第2版)」のP247~248にあるプログラムに関する質問です。

自分なりに実行順序に番号を付けてみました。
①から⑤までは一直線に進むのですが、⑥のところで、initialaizeメソッドに進む部分とクラスメソッド戻り値をusesrsに入れる部分とに分かれるように見えて混乱しています。
⑥のところでは、create_user(names)の戻り値として、 ['Alice', 'Bob', 'Carol']が戻ると理解しています。
そのため、この戻り値は、③の処理が全部終わってから戻るように思えます。
一方、⑤のUser.new(name)は逐次的に実行されて、⑥のinitializeを実行し、⑦で、@nameを作成しているように思えます。

この順番だと、最後の⑨と⑩が実行されるときには、@nameは'Alice' → 'Bob' → ´Carol' と上書きを重ねて、
’Carol'しか残っていないように思えます。

どうして、users = create_user(names) でまとめて渡された配列のその後の処理と、 逐次的に実行されたUser.new(name)で作成された
@names の結果が、⑩のところで、ぴったりと合うかがわかりません。

この考え方のどこが間違っているのか、どう理解すればいいのか教えて頂ければ有難くぞんじます。

Ruby

1class User 2 def initialize(name)  ←⑥ (⑤のuser.newのときに呼ばれる) 3 @name = name ←⑦ 4 end 5クラス名.メソッド名 6# self.を付けるとクラスメソッドになる 7 def self.create_users(names) ←③ 8 names.map do ¦name¦  ←④ 9 User.new(name)  ←⑤ 10 end 11end 12# これはインスタンスメソッド 13 def hello ← ⑨ 14 "Hello, I am #{@name}."  ⑩ 15 end 16end 17names = ['Alice', 'Bob', 'Carol'] ←① 18# クラスメソッドの呼び出し 19users = User.create_users(names)   ←② ←⑥配列オブジェクトをusersに入れる。 20users.each do ¦user¦          ←⑦ 21# インスタンスメソッドの呼び出し 22 puts user.hello             ←⑧ 23end 24#=> Hello, I am Alice. 25# Hello, I am Bob. 26# Hello, I am Carol.

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

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

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

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

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

pg1965

2022/04/26 16:58

質問を出した後に再度考えてみたのですが、 ⑥で受け取った配列オブジェクトは各々のオブジェクトの中に、initializeメソッドで作成された@nameを含んでいるため、@nameが上書きされることはないと理解できるようになりました。⑩のhelloメソッドにある@nameもinitializeメソッドから直接@nameを引っ張ってきているわけではなく、配列オブジェクトの中に含まれている@nameを利用していると理解しました。このような理解で正しいでしょうか。
guest

回答2

0

なかなか理解できるように説明するのは難しいですね。

⑥のところで、initialaizeメソッドに進む部分とクラスメソッド戻り値をusesrsに入れる部分とに分かれるように見えて混乱しています。

順番的にはUser.new(name)  ←⑤でオブジェクト生成、生成時にdef initialize(name)  ←⑥が実行され@name = name ←⑦が実行、それをnames.map do |name|  ←④のusersの配列の数だけ繰り返し、全ループが完了したらusers = User.create_users(names)   ←②のusers変数に値を格納します。
番号で言うと②③④[⑤⑥⑦(Alice)][⑤⑥⑦(Bob)][⑤⑥⑦(Carol)]で、その次に配列オブジェクトをusersに入れる。
になります。
なので、「配列オブジェクトをusersに入れる。」は⑥ではなくて⑧になると思います。

ruby

1class User 2 def initialize(name)  ←⑥ (⑤のuser.newのときに呼ばれる) 3 @name = name ←⑦ 4 end 5クラス名.メソッド名 6# self.を付けるとクラスメソッドになる 7 def self.create_users(names) ←③ 8 names.map do |name|  ←④ 9 User.new(name)  ←⑤ 10 end 11end 12# これはインスタンスメソッド 13 def hello ← ⑪ 14 "Hello, I am #{@name}."  ⑫ 15 end 16end 17names = ['Alice', 'Bob', 'Carol'] ←① 18# クラスメソッドの呼び出し 19users = User.create_users(names)   ←② ←⑧配列オブジェクトをusersに入れる。 20users.each do |user|          ←⑨ 21# インスタンスメソッドの呼び出し 22 puts user.hello             ←⑩ ←⑬putsで値を表示 23end 24#=> Hello, I am Alice. 25# Hello, I am Bob. 26# Hello, I am Carol.

ループの部分をもう少し分かりやすくすると以下の様なコードになるかと思います。

ruby

1def self.create_users(names) ←③ 2 userList = names.map do |name|  ←④ 3 return User.new(name)  ←⑤ 4 end 5 6 return userList 7end 8 9# 多分上記のコードは正常に動作しないので、現実的なものを書くと 10def self.create_users(names) ←③ 11 userList= names.map { |name|  ←④ 12 return User.new(name)  ←⑤ 13 } 14 15 return userList 16end

rubyはreturnを省略が可能で、省略された場合一番最後のコードが返却されます。
names.mapに関してはUser.new(name)のリストが返却、def self.create_users(names)に関しては、names.mapの結果つまりUser.new(name)のリストが返却されます。

⑥のところでは、create_user(names)の戻り値として、 ['Alice', 'Bob', 'Carol']が戻ると理解しています。

自分の理解だと少し違って、戻り値は以下だと認識しています。
[User<xxxxx>, User<yyyy>, User<zzzz>]
(多分インスタンスにIDが振られて表示される記憶です)
つまり、①で定義した['Alice', 'Bob', 'Carol']それぞれのUserインスタンスという理解です。
(既存の回答はわかりやすいように記述したのかもしれません。個人的にはnewで生成されたインスタンスが返却されてusersに格納される気がします)

試しにusers = User.create_users(names)users.each do |user|の間またはループ内のputs user.helloの上にprint(p)を入れてみてはどうでしょうか。
多分Userのインスタンスが入っていると思います。

ruby

1names = ['Alice', 'Bob', 'Carol'] ←① 2 3# クラスメソッドの呼び出し 4users = User.create_users(names)   ←② ←⑥配列オブジェクトをusersに入れる。# ***追記①*** 5p users[0] 6 7users.each do |user|          ←⑦ 8# インスタンスメソッドの呼び出し 9 # ***追記②*** 10 p user 11 puts user.hello             ←⑧ 12end 13

オブジェクト指向の書籍等でよく表現されているように、クラスは設計図、実態はオブジェクトなので、Userクラスの中でUser.new()をしている為、newしたその都度インスタンスが生成され、最初にinitialize関数が実行されます。

@nameは'Alice' → 'Bob' → ´Carol' と上書きを重ねて、’Carol'しか残っていないように思えます。

この考え方は、create_users(names)の中でclass Userの@nameの値にデータが入っているイメージをされているのではないでしょうか。
そうではなくて、Userクラスはあくまでも設計図で、コードではnewでインスタンスを個別に生成している為、上書きはされません。

他の言い方をすると、class Userは内部でUser.new(name)を呼び出しています。
自身のクラス内で自身のオブジェクトを生成することはあると思います。

色々な方向から説明をしてみましたが、どうでしょうか。
(内容間違えていたらすみません)

投稿2022/04/27 02:44

YuuT

総合スコア673

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

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

pg1965

2022/04/27 04:17

詳しいご説明をありがとうございました。Rubyへの理解が深まりました。感謝いたします。
pg1965

2022/04/27 06:00

>print(p)を入れてみてはどうでしょうか やってみます。ありがとうございました。
guest

0

ベストアンサー

⑥のところでは、create_user(names)の戻り値として、 ['Alice', 'Bob', 'Carol']が戻ると理解しています。

いえ、次のようになります。

ruby

1[User.new('Alice'), User.new('Bob'), User.new('Carol')]

User インスタンスはそれぞれに @name を管理していますので、上書きすることはありません。

投稿2022/04/26 18:56

mather

総合スコア6753

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

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

pg1965

2022/04/27 01:35

[User.new('Alice'), User.new('Bob'), User.new('Carol')]が戻り値だとすると、User.new('Alice')が実行されて、initializeメソッドが動くのはどのタイミングになるのでしょうか。恐れ入りますが、よろしくお願いします。
mather

2022/04/27 02:56

こういう値が返る、という表現です。(Userインスタンスを直接表現する方法がないので) 実際にはUser.new('Alice')を実行して生成されるインスタンスが配列に入ったものです。
pg1965

2022/04/27 04:15

>実際にはUser.new('Alice')を実行して生成されるインスタンスが配列に入ったものです。 よくわかりました。 Userインスタンスを直接表現する方法はないんですね。丁寧にご説明いただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問