0

私は経験豊富な Obj-C/Java プログラマーで、Ruby を始めています。もちろん、これほど動的であるという事実は素晴らしいことです (クラスを再開できるのは素晴らしいことです!) が、Ruby コードを書き始めたときに、私を悩ませたり心配させたりすることが 1 つあります。

独自のクラスで iVar のタイプを明示的に設定するために、Ruby er が (もしあれば) 何をするかを知りたいです。私が見る限り、iVar を任意のオブジェクトに設定でき、Ruby は文句を言いません。ただし、特定の iVar が特定のタイプであると予想される場合は、後で問題が発生する可能性があります。例えば:

class MyString
  def initialize(myString)
    @myString = myString
  end

  def uppercase_my_string
    @myString.upcase
  end
end

st1 = MyString.new("a string!")
st1.uppercase_my_string

st2 = MyString.new(["a string"])
st2.uppercase_my_string

NoMethodErrorもちろん、配列にはメソッドがないため、このコードは をスローしupcaseます。残念ながら、実際にどこが間違っていたのか (上記の行、作成時str2) はわかりません。そのため、デバッグ時にはあまり役に立ちません (str2目立たない場所にいくつかのモジュールが作成された場合)。次のようにいくつかのチェックinitialize

class MyString
  def initialize(myString)
    raise TypeError, "myString iVar is not a string!" unless myString.class == String
    @myString = myString
  end
end
...same code as before

これで、誤って新しい MyString を作成してしまった場合、自分がいかに愚かであったかを知らされます (さらに重要なのは、失敗したときではなく、いつ作成したかを知らされることです。入力するのは少し面倒ですが、問題ありません。私の次の問題attr_accessorsiVar で使用することを決定したときです。

class MyString
  attr_accessor :my_string
  def initialize(my_string)
    raise TypeError, "myString iVar is not a string!" unless my_string.class == String
    @my_string = my_string
  end

  def uppercase_my_string
    @my_string.upcase
  end
end

st1 = MyString.new("a string!")
st1.uppercase_my_string

st2 = MyString.new("good, it's a string")
st2.my_string = ["an array!"]
st2.uppercase_my_string

定義されたセッターを使用すると、非常にこっそりとエラー チェックを回避できますinitializeuppercase_my_string繰り返しますが、これには、誤っ@my_stringて配列に設定した場合ではなく、例外をスローするという問題があります。

最後に、アクセサーを手動で作成してエラー チェックを追加することもできますが、これは非常に面倒です...これを行うためのより迅速で簡単な方法はありますか。それとも、私は心を閉ざしていて、十分にダイナミックではありませんか?

ありがとう!


余談ですが、Obj-C でも実行時に同じ問題が発生することはわかっていますが、通常、型のオブジェクトを型arrayの変数string(または類似のもの) に代入しているというコンパイラ エラーが表示されるので、少なくともどこで発生するか警告されます

4

2 に答える 2

4

実際には、この種の型の問題は実際には非常にまれです。偏執的になりたい場合は (彼らは本当にあなたを捕まえるために)、入力を送信してto_s、常に文字列があることを確認できます。

def initialize(my_string)
  @my_string = my_string.to_s
end

その後、言うことができMyString.new(6)、すべてが期待どおりに機能します。もちろん、あなたはMyString.new([6, 11])ナンセンスを言うことができます。

本当に String になりたい場合はmy_string、その を明示的にチェックしませんclass。誰かが String をサブクラス化した場合、それは問題を引き起こすので、少なくとも以下を使用したいでしょうis_a?:

def initialize(myString)
  raise TypeError, ... unless myString.is_a? String
  @myString = myString
end

to_str確認できる方法もあります。

def initialize(myString)
  raise TypeError, ... unless myString.respond_to? :to_str
  @myString = myString.to_str
end

そのメソッドを実装すると、(一部のサークルでは) あなたのものが String であるほど十分に String に似ていることを示します。呼び出しはより良いアイデアだと思いますto_s.Rubyで人々が期待するように物事がより動作するようになります.

あなたのミューテーターの問題に関する限り:

st2.my_string = ["an array!"]

プロパティに必要なものをだれかに書き込む必要はありません。クラスは構造体ではありません。アクセサーを自動的に定義し、独自のミューテーターを記述して、to_s呼び出しを自動的に挿入することしかできません。

class MyString
  attr_reader :my_string
  def initialize(my_string)
    self.my_string = my_string
  end

  def my_string=(s)
    @my_string = s.to_s
  end

  def uppercase_my_string
    @my_string.upcase
  end
end

基本的に、Ruby では型はあまり気にせず、何かがどのメソッドに応答するかを気にします。また、特に文字列にしたい場合は、ユニバーサルto_sメソッドを呼び出して文字列にします (文字列補間"#{x}"が行います)。

于 2013-05-19T07:15:34.023 に答える