1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

動かして学ぶrubyのアクセサメソッドの使い分け&エラー解決の近道のお話

Posted at

はじめに

どうもこんにちは~
クラスを書く時に必要なフィールド変数
最初はattr_accessorメソッドで良いだろうと高を括っていました。
調べていくうちにオブジェクト指向のカプセル化にも関わってくる重要な項目だと分かったので
自分への備考禄&知らない方へのヒントになればいいなと思い記事を書きました。
物凄く記事が長いです。お時間があるときに読むことをおすすめします。

この記事の対象読者

・Ruby初学者の方
・取り合えずインスタンス化までは出来るぞって方
・アクセサメソッド知ってるけど使い道が分からない方

動かして学んでみよう

動かしながら学んでいってみましょう。この後提示するクラスの内容はどうでもいいので
コピペしてもらって結構です。しかしアクセサの理解があやふやな方はターミナルでの実行は必ずしておいてください。動かして「どういった動きをするのか」を見ておくのと見ておかないとでは大違いです。この機会に「動かす習慣」を付けてみてください。一緒に頑張りましょう。

目次

アクセサメソッドとは
・実験してみよう
アクセサメソッドなし
attr_reader
attr_writer
attr_accessor
・考察してみよう

アクセサメソッドとは

アクセサメソッドとは
3種類あります

attr_reader (読み取りできるぞ)
attr_writer (書き込みできるぞ)
attr_accessor (どっちもできるぞ)

ざっくりできることはこんな感じだって頭の片隅に入れといてください。

アクセサメソッドなし

例えば「1~n番目まで順番に入る配列を作れる」クラスを作ったとします。
アクセサメソッドを一旦全部書いてみましょう。
attr_reader :array
attr_writer :array
attr_accessor :array
そして全部コメント化してください。
実験していきます。

class NumberArrayMaker
  #attr_reader :array
  #attr_writer :array
  #attr_accessor :array
  
  def initialize(number)
    @array = make_number_array(number)
    #[1,2,3,4...,number]の配列が入る
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
      #[1,2,3,4...,number]までの配列をメソッド内変数に格納
    end
    number_array
    #できた配列返すよ~
  end
end

クラス自体はどうでもいいです。取り合えずインスタンス化して
インスタンスの中身を参照見てみましょう。
インスタンスの中身の変数やメソッドの参照は
インスタンス.インスタンス変数名 or インスタンスメソッド名で見れます。
前にpやputなどで出力することをお忘れなく。ではやってみましょう。

create_array = NumberArrayMaker.new(12)

p create_array.array
#=> `<main>': undefined method `array' for #<NumberArrayMaker:0x000001afe08edb90 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)

見れませんね。エラーが出ます。エラー文も読んでみましょう。
エラー内容は
「arrayなんて名前のメソッドないぞ」と怒ってますね。
今のところ分かったことは「アクセサメソッド無しだと参照はできない」ということが分かりました。一歩前進です。それでは
「代入」の方はどうでしょうか。
インスタンス変数に代入するには
インスタンス.インスタンス変数名 = "値"
で代入出来ます。やってみましょう。

p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=><main>': undefined method `array=' for #<NumberArrayMaker:0x000001d1434d4ea8 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)

やっぱり見れませんね。エラーが出ます。エラー文も読んでみましょう。
エラー内容は
「arrayなんて名前のメソッドないぞ」と怒ってますね。同じですね。
これで「アクセサメソッド無しだと代入はできない」ということが分かりました。

アクセサメソッドなし
「参照や代入しようとしても、『メソッドがないぞ』と怒られる。」

attr_reader

はい。ではattr_readerのコメント化を解除してください

class NumberArrayMaker
  attr_reader :array
  #attr_writer :array
  #attr_accessor :array
  
  def initialize(number)
    @array = make_number_array(number)
    #[1,2,3,4...,number]の配列が入る
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
      #[1,2,3,4...,number]までの配列をメソッド内変数に格納
    end
    number_array
    #できた配列返すよ~
  end
end

やることはさっきと同じです
まずはcreate_array.arrayの「参照」からチェックしていきます

p create_array.array
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

お、出ましたね!
どうやら今回は参照出来たようです。
これで「attr_reader」を付けると「参照することができる」
事が分かりました。
次は「代入」です。

p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=> undefined method `array=' for #<NumberArrayMaker:0x00000207871d70c8 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)

はい。親の顔より見たエラーです。めんどくさいと思うかもしれませんが絶対にエラーは読むようにしましょう。undefined method `array=` (NoMethodError)つまりこれも
「arrayって名前のメソッドが何処にもないぞ」と怒っているわけですね。
ではまとめていきます

attr_reader
「参照は出来た。代入しようとすると『メソットがないぞ』と怒られる」

attr_writer

はい。ではattr_readerをコメント化し
はい。ではattr_writterのコメント化を解除してください

class NumberArrayMaker
  # attr_reader :array
  attr_writer :array
  #attr_accessor :array
  
  def initialize(number)
    @array = make_number_array(number)
    #[1,2,3,4...,number]の配列が入る
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
      #[1,2,3,4...,number]までの配列をメソッド内変数に格納
    end
    number_array
    #できた配列返すよ~
  end
end

同じことを繰り返していきます。先ずは「参照」から
地道に、地道にやっていきます。

p create_array.array
#=> `<main>': undefined method `array' for #<NumberArrayMaker:0x0000018279c8d078 @array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]> (NoMethodError)

エラーを見ていきます。undefined method `array'(NoMethodError)
これもarrayメソッドがない為呼び出せずエラーが出ていますね。
それでは「代入」はどうでしょうか
これで「参照」はできないことが分かりました。

p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=> ["すし", "いなりずし", "ふなずし"]

出来ましたね!代入が出来ることが分かりました。
それではまとめましょう

attr_writer
「代入することは出来た。参照しようとすると『メソットがないぞ』と怒られる」

どうですかね。長かったですが「何が問題」かわかってきたんじゃないですかね。
さあ、次で最後ですよ。

attr_accessor

それではattr_writer :arrayをコメント化してください
attr_accessor :arrayのコメント化を解除してください

class NumberArrayMaker
  # attr_reader :array
  # attr_writer :array
  attr_accessor :array
  #[1,2,3,4...,number]の配列が入る
  
  def initialize(number)
    @array = make_number_array(number)
  end

  def make_number_array(number)
    number_array = []
    
    (1..number).to_a.each do |n|
      number_array << n
    end
    number_array
  end
end

では「参照」から…

p create_array.array
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

実行できますね。
それでは「代入」はどうかな…

p create_array.array = ["すし", "いなりずし", "ふなずし"]
#=> ["すし", "いなりずし", "ふなずし"]

両方とも出来ましたね!
ではまとめていきます

attr_accessor
「参照は実行できた。代入も実行できた」

考察してみよう

皆さんお疲れ様でした!これでアクセサメソッドの「実験」は終わりです。
長かったですよね。でも大事なことです。なぜなら実験結果から「仮説」「考察」をつけ
「何が問題だったのか」の「あたり」を付けることができるからです。
実際に考察してみましょう!
実験結果は以下の通りです

アクセサメソッドなし
「参照や代入しようとしても、『メソッドがないぞ』と怒られる。」

attr_reader
「参照は出来た。代入しようとすると『メソットがないぞ』と怒られる」

attr_writer
「代入することは出来た。参照しようとすると『メソットがないぞ』と怒られる」

attr_accessor
「参照は実行できた。代入も実行できた」

それではエラーが起きたときの共通項から考えていきましょう
エラーが起きたときには必ず「メソッドがない」とエラーが出ますね。
つまりここで考えられるのは「アクセサメソッドはメソッドと関連しているんだろう」と「あたり」がつけられます。
もっと言うと「メソッドを作ってるんじゃね?」ってところまで考察できるはずです

ネタばらし

クラスに以下のメソッドを追加してください
アクセサメソッドはもういりません。コメント化するか削除してください

  def array
    @array
  end

  def array=(value)
    @array = value
  end

これで以下を実行してください

p create_array.array
p create_array.array = ["すし", "いなりずし", "ふなずし"]

どうですか。分かりましたか?
つまり本当にただメソッドが無かったということが分かったと思います。

  def array
    @array
  end

これは「attr_reader」が自動で作ってくれていました

  def array=(value)
    @array = value
  end

これは「attr_writter」が自動で作ってくれていました
そして「attr_accessor」はどちらも同時に作ってくれていたんですね。

エラー解決の近道のお話

お疲れ様でした。大変だったと思います。途中から「言いたい事分かったよ。同じ事何度も何度もくどいよ」と思った方もいるかもしれません。
しかし僕がここで皆さんにお伝えしたかったのは
分からないことを何となくではなく「なぜそうなのか」をテストし、考察する過程を踏むことで
「それが何なのか」が分かるようになるということです。
確かにchatGPTに頼れば簡単に答えを教えてくれるかもしれませんし、「これってどういう意味?」と聞けば調べずともそれが何か教えてくれます。
でもchatGPTが使えなくなったらどうでしょう、自力で書けますか?自分で調べたこともテストしたこともないのに問題解決できますか?と僕は考えています。
実験し、問題点を洗い出し、考察し、あたりを付けて直してみる
この繰り返しがプログラミング学習の近道なのではないかと僕は思っています。
泥臭く、地味で地道な作業です。でもその先に「作ってくれてありがとう」そう言ってくれる人が
いると思うと「今日も頑張ろう」と勉強に熱が入ります。
僕はプログラミングし始めてまだ3か月程度の初心者ですが同じ境遇の方、これから始めようとしている方。頑張っていきましょう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?