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

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

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

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

Q&A

解決済

3回答

1771閲覧

【Ruby】selfの意味が分からない

SIByL

総合スコア11

Ruby

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

1グッド

4クリップ

投稿2018/03/05 05:31

編集2018/03/05 07:38

秋山智俊『恋するプログラム - Rubyでつくる人工無能』読んでいてわからない箇所がありました。コードの最後に書かれてある「self」という部分です。どこから湧いて出たんですか?どういう意味なんですか?

Ruby

1require "unmo" 2require "vr/vruby" 3require "vr/vrcontrol" 4require "vr/handler" 5require "nobycanvas" 6 7class NobyForm < VRForm 8 include VRDrawble 9 include VRMenuUseable 10 11 def construct 12 #ノビィ作成(人工無能のことです) 13 @noby = Unmo.new("noby") 14 15 #ウィンドウタイトル 16 self.caption = "Unmo System : " + @noby.name #下の画像の部分です

イメージ説明

tomo.oshima0828👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

まず「レシーバー」という概念について説明します。

メソッドというものは,かならず何らかのオブジェクトに対して呼び出されます。
例えば

rb

1str = "Ruby" 2str.downcase #=> "ruby"

の場合,downcase というメソッドはローカル変数 str が指している String オブジェクト("RUby")に対して呼び出されています。

この,対象となるオブジェクトを,そのメソッドのレシーバー(receiver)と呼びます。
(なぜ「受け手」などと呼ぶのか,という話は割愛)

メソッド呼び出しのピリオドの前には,変数だけでなく一般に式を書くことができます。式の評価結果をレシーバーとしてメソッドが呼び出されます。
例えば

rb

1(1 + 3).even? #=> true

の場合,(1 + 3) という式の評価結果である整数 4 に対して,even? メソッド(偶数かどうかを判定するメソッド)が呼び出されています。

次に暗黙のレシーバーについて説明します。

さきほどのメソッド呼び出しの例では,レシーバーがあらわに書かれていました。
しかし,

rb

1puts 3

の場合,puts もメソッドですが,レシーバーが書かれていません。
こんなふうに,レシーバーを省略したメソッド呼び出しも可能です。
レシーバーを略した場合,self というものがレシーバーになるというルールです。
上の例は,

rb

1self.puts(3)

とまったく同じです。これを省略して書いただけです。

いろいよ self の説明に入っていきます。

まず,self という四つの文字からなる識別子は「擬似変数」と呼ばれるものの一つです。
擬似変数の仲間には niltrue など,どこで参照しても常に同じオブジェクトを指しているものもありますが,self の場合は文脈によって指しているオブジェクトが変わります。
余談ですが,現在のソースファイル(スクリプトファイル)のファイル名を指している __FILE__ という擬似変数もあります。こちらも,参照する場所(ファイル)によって異なる文字列を指します。

ともかく,self は何らかのオブジェクトを指しています。
以下,話を簡単にするため,「メソッド定義の中における self」に限って説明します。
self はそのメソッドの実行主体,つまりレシーバーを指しています。

具体例を挙げます。以下のコードを見てください。

rb

1# source-1 2class Hoge 3 def hello 4 puts "Hello, my object_id is #{self.object_id}." 5 end 6end 7 8x = Hoge.new 9x.hello # => "Hello, my object_id is 43074640."

上の例で,hello メソッドの中で self.object_id という式が出てきますね。
self に対して object_id メソッドを呼び出しています。object_id はオブジェクトの ID(全てのオブジェクトが持つ,オブジェクト固有の整数)を返すメソッドです。
その返り値を文字列に埋め込んでいるのですね。
オブジェクトにどんな ID が振られるかは不定なので,同じプログラムを後日実行したら,出てくる数字は変わりえます。

この selfhello メソッドのレシーバーを指しています。
上の実行例では,ローカル変数 x が指しているオブジェクトがそれです。hello メソッドは,そいつの ID を表示して挨拶するメソッドというわけです。

これで,一応 self の説明ができたことになります。

しかし,こんな疑問が湧いてきます。
レシーバーを省略してメソッド呼び出しを書くと self がレシーバーになるのだったら,上の例でも self. を省いて

rb

1# source-2 2class Hoge 3 def hello 4 puts "Hello, my object_id is #{object_id}." 5 end 6end

と書いてもいいんじゃないの?

そのとおりです。この修正版はうまく働きます。

ただ,たとえ self をレシーバーとするときでも,省略できない場合があります。

例えば,メソッド名と同じローカル変数を使っている場合。

rb

1# source-3 2class Hoge 3 def hello 4 object_id = "foo" 5 puts "Hello, my object_id is #{object_id}." 6 end 7end

実は単に object_id とだけ書くと,形の上ではローカル変数の参照なのかメソッド呼び出しなのか区別が付きません。
source-2 の場合,ローカル変数がどこにも定義されていない(ローカル変数への代入がどこにも無い)ので,object_id はメソッド呼び出しだと解釈されます。(そういうルールです)。
source-3 の場合,ローカル変数が定義されたあとなので,object_id はローカル変数の参照だと解釈されてしまいます。

self. が省略できない例をもう一つ挙げます。

rb

1# source-4 2class Hoge 3 def hello 4 puts "Hello, I am an instance of #{self.class}." 5 end 6end 7 8x = Hoge.new 9x.hello # => "Hello, I am an instance of Hoge."

今度は,自身が何のクラスのインスタンスかを表示して挨拶します。
source-4 で self. を省略すると,class の部分がメソッド呼び出しではなくクラス定義の冒頭かと勘違いされ,(直後にクラス名が書いてないので)SyntaxError となります。

ここからがいよいよ核心です。

まずは代入メソッドと呼ばれるものを説明します。

代入メソッドはメソッド名の末尾が = であるようなメソッドですが,インスタンス変数に外部から値をセットするのが典型的な使い方です。
以下の例をご覧ください。

rb

1class Person 2 def name=(name) 3 @name = name 4 end 5 6 def name 7 return @name # return は省略可 8 end 9end 10 11x = Person.new 12x.name = "Richard" 13puts x.name #=> "Richard"

代入メソッドの面白いところは,上の例のように,使うときに = の前にスペースを入れても構わないことです。
ふつう,メソッド名の途中にスペースなんか入れたらダメですが,代入メソッドは文法上特別扱いなんですね。
でもメソッドであることは変わりません。

この

rb

1x.name = "Richard"

は,いかにも(名前のとおり)代入ぽいですが,れっきとしたメソッド呼び出しです。
ローカル変数 x が指す Person オブジェクトをレシーバーとし,文字列 "Richard" を引数とした,メソッド name= の呼び出しなんです。

ところで,この代入メソッドを,Person クラスの他のメソッドから利用するとします。

たとえば,他人と同じ名前をつける named_after というメソッドを考えましょうか。(誰かの名にちなんで命名すること)

こんなふうに使います。

rb

1person1 = Person.new 2person1 = "Eaves" 3 4person2 = Person.new 5person2.named_after person1 6 7puts person2.name #=> "Eaves"

このメソッドはこんなふうに書けますね:

rb

1def named_after(other) 2 self.name = other.name 3end

named_after メソッドの中で,自分自身の name= メソッドを呼び出しているのです。

えー,実は今の場合,代入メソッドを呼び出さなくてもインスタンス変数 @name に直接代入すればいいのですが,説明のためにあえてこうしました。
(現実の仕事では,代入メソッドを使うべきシチュエーションがよくあるのですが,本題と関係ないので割愛)

このメソッドでは self. が省略できません。なぜなら

rb

1def named_after(other) 2 name = other.name 3end

と書くと,ローカル変数への代入と解釈されてしまうからです。

これがご質問の答えとなる self の正体です。

(力尽きた・・・)

投稿2018/03/05 13:19

scivola

総合スコア2108

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

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

SIByL

2018/03/07 05:55

scivolaさん 回答ありがとうございます。こんなに詳しく分かりやすく説明してくださって感激しています。selfの使い方や@変数の外部からの操作など、勉強になる点がたくさんありました。教科書よりもわかりやすかったのでノートに取らせていただきました。
guest

0

selfが分からないと言う事は、オブジェクト指向プログラミングについて学んでいないと言う事だと思いますが、
この本をAmazonで情報を見ると、出版社からのコメントとして、

Rubyプログラミングの実践的入門書としても優れています。

また、レビューとして、

Rubyの入門書としても利用できる。

と書いてあるので、本の中でオブジェクト指向について説明した部分があるかと思います。
そこを読んでください。
ここの回答欄でオブジェクト指向についてゼロから説明するのは難しいです。

投稿2018/03/05 06:59

otn

総合スコア84499

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

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

SIByL

2018/03/07 05:31

otnさん 回答ありがとうございます。残念ながら本書はコードを書いて覚える本なので、オブジェクト指向について詳しくは説明されていません。
otn

2018/03/07 07:01 編集

そうなんですね。ということは、レビューの文言がおかしいのか。あるいは、他の言語の中上級者向けのRuby入門書なのか。 であれば、適当なRuby入門書をまず読むのが良いかと思います。
guest

0

Rubyはやっていませんからわかりませんが。

まず、ソースコードが読みづらいです。

Ruby インデント

インデントがないと読みにくいです。

teratailには ソースコード用のものがあるのでそれを利用してください。

"</>" ボタンを押して、出てきたやつの中にソースコードを記述してください。

次に質問内容について。

たぶん、このselfっていうやつは 他の言語だと this に相当するやつだと思います。

自分オブジェクトのメンバを指定するときに使う。

よって、

self.caption = "hello"

だとしたら、そのオブジェクト(自分自身)のcaptionメンバ ( フィールドかもしれないし、メソッドかもしれないが。 ) に "hello" を代入している

ってことになる。

投稿2018/03/05 05:41

BeatStar

総合スコア4958

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

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

SIByL

2018/03/07 05:25

BeatStarさん 回答ありがとうございます。selfは自分自身のオブジェクトを指しているのですね。例文をつかったご説明は大変分かりやすいものでした。 また、インデントの不備に関しては申し訳ありませんでした。イラッとさせないように今後は気をつけようと思います。
BeatStar

2018/03/07 05:33

イラっとはしていませんが、読みにくかったので。 ( 上記の "イラッと..."は私の言葉じゃないですが。 ) selfについての 詳しい話は scivolaさんのアンサー等を参照してください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問