سؤال

class Hello
@hello = "hello"
    def display
        puts @hello
    end
end

h = Hello.new
h.display

لقد قمت بإنشاء الفصل أعلاه.لا يطبع أي شيء.اعتقدت أنه تم تعيين متغير المثيل @hello أثناء إعلان الفصل.ولكن عندما أستدعي طريقة العرض يكون الإخراج "لا شيء".ما هي الطريقة الصحيحة للقيام بذلك؟

هل كانت مفيدة؟

المحلول

قد تكون متغيرات الحالة في روبي مربكة بعض الشيء عند تعلم روبي لأول مرة، خاصة إذا كنت معتادًا على لغة OO أخرى مثل Java.

لا يمكنك ببساطة الإعلان عن متغير مثيل.

أحد أهم الأشياء التي يجب معرفتها حول متغيرات الحالة في روبي، بصرف النظر عن التدوين الذي يحتوي على بادئة علامة @، هو أنه إنهم ينبضون بالحياة في المرة الأولى التي يتم فيها تكليفهم بذلك.

class Hello
  def create_some_state
    @hello = "hello"
  end
end

h = Hello.new
p h.instance_variables 

h.create_some_state
p h.instance_variables

# Output
[]
["@hello"]

يمكنك استخدام الطريقة Object#instance_variables لسرد كافة متغيرات مثيل الكائن.

عادةً ما تقوم "بإعلان" كافة متغيرات المثيلات وتهيئتها في طريقة التهيئة.هناك طريقة أخرى للتوثيق الواضح لمتغيرات الحالة التي يجب أن تكون متاحة للعامة وهي استخدام أساليب الوحدة النمطية attr_accessor (قراءة و كتابة)، attr_writer (اكتب و attr_reader (يقرأ).ستقوم هذه الطرق بتجميع طرق وصول مختلفة لمتغير المثيل المدرج.

class Hello
  attr_accessor :hello
end

h = Hello.new
p h.instance_variables 

h.hello = "hello"
p h.instance_variables

# Output
[]
["@hello"]

لا يزال لم يتم إنشاء متغير المثيل حتى يتم تعيينه لاستخدام ملف Synthesized Hello#hello= طريقة.

هناك مشكلة أخرى مهمة، كما وصفها kch، وهي أنك بحاجة إلى أن تكون على دراية بالسياقات المختلفة النشطة عند الإعلان عن الفصل الدراسي.عند الإعلان عن فئة جهاز الاستقبال الافتراضي (الذاتي) في النطاق الخارجي سيكون الكائن الذي يمثل الفئة نفسها.ومن ثم، سيقوم الكود الخاص بك أولاً بإنشاء متغير مثيل للفئة عند التعيين إلى @hello على مستوى الصف.

الأساليب الداخلية الذات سيكون الكائن الذي يتم استدعاء الطريقة عليه، ومن ثم فإنك تحاول طباعة قيمة متغير مثيل بالاسم @hello في الكائن، وهو غير موجود (لاحظ أنه من القانوني تمامًا قراءة متغير مثيل غير موجود).

نصائح أخرى

وتحتاج إلى إضافة وسيلة initialize:

class Hello
    def initialize
        @hello = "hello"
    end
    def display
        puts @hello
    end
end

h = Hello.new
h.display

ويسمى @hello أولا في التعليمات البرمجية متغير مثيل فئة.

وانها متغير مثيل كائن الفئة التي يشير Hello المستمرة ل. (والذي هو مثيل Class الدرجة).

ومن الناحية الفنية، عندما كنت في نطاق class، يتم تعيين self بك إلى كائن من الدرجة الحالية، و@variables تتعلق إلى self الحالية الخاصة بك. صبي أمتص في شرح هذه الأمور.

ويمكنك الحصول على كل هذا وأكثر من ذلك بكثير أوضح لك بمشاهدة <لأ href = "http://www.pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming" يختلط = "noreferrer"> هذه المجموعة من $ 5 لكل قطات للشاشة من المبرمجون عملي .

و(أو يمكنك أن تطلب توضيحات هنا وسأحاول لتحديث.)

هناك وصف واضح في كتاب "لغة برمجة الياقوت"، اقرأه سيكون مفيدًا جدًا.ألصقه هنا (من الفصل 7.1.16):

متغير مثيل يستخدم داخل تعريف فئة ولكن خارج تعريف أسلوب المثيل هو متغير مثيل الفئة.

class Point
    # Initialize our class instance variables in the class definition itself
    @n = 0              # How many points have been created
    @totalX = 0         # The sum of all X coordinates
    @totalY = 0         # The sum of all Y coordinates

    def initialize(x,y) # Initialize method 
      @x,@y = x, y      # Sets initial values for instance variables
    end

    def self.new(x,y)   # Class method to create new Point objects
      # Use the class instance variables in this class method to collect data
      @n += 1           # Keep track of how many Points have been created
      @totalX += x      # Add these coordinates to the totals
      @totalY += y

      super             # Invoke the real definition of new to create a Point
                    # More about super later in the chapter
    end

    # A class method to report the data we collected
    def self.report
        # Here we use the class instance variables in a class method
        puts "Number of points created: #@n"
        puts "Average X coordinate: #{@totalX.to_f/@n}"
        puts "Average Y coordinate: #{@totalY.to_f/@n}"
    end
end

......

لأن متغيرات مثيل الفئة هي مجرد متغيرات مثيل للفئة الكائنات ، يمكننا استخدام ATTR و attr_reader و attr_accessor لإنشاء طرق الوصول لهم.

class << self
  attr_accessor :n, :totalX, :totalY
end

بعد تحديد هذه الموصلات، يمكننا الإشارة إلى بياناتنا الأولية باسم Point.n وPoint.totalX وPoint.totalY.

لقد نسيت أن هناك مفهوم "متغير مثيل الفئة" في روبي.على أي حال، بدت مشكلة OP محيرة، ولم يتم تناولها حقًا في أي من الإجابات حتى الآن، باستثناء تلميح في إجابة kch:إنها مشكلة النطاق.(أضيفت عند التعديل:في الواقع، إجابة sris يفعل قم بمعالجة هذه النقطة في النهاية، لكنني سأترك هذه الإجابة قائمة على أي حال، حيث أعتقد أن رمز المثال قد يكون مفيدًا لفهم المشكلة.)

في فئة روبي، اسم متغير يبدأ بـ @ يمكن الرجوع إلى واحد من اثنين المتغيرات:إما إلى المتغيرات الخاصة أو إلى أ متغير مثيل الفئة, ، اعتمادًا على مكان الفصل المشار إليه.هذا هو مسكتك خفية إلى حد ما.

مثال سوف يوضح هذه النقطة.إليك فئة اختبار روبي صغيرة (تم اختبار جميع الأكواد في irb):

class T

  @@class_variable = "BBQ"
  @class_instance_variable_1 = "WTF"
  @class_instance_variable_2 = "LOL"

  def self.class_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def initialize
    @instance_variable = "omg"
    # The following line does not assign a value to the class instance variable,
    # but actually declares an instance variable withthe same name!
    @class_instance_variable_1 = "wtf"
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def instance_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

end

لقد قمت بتسمية المتغيرات وفقًا لما اعتقدت أنها كذلك، على الرغم من أن هذا ليس هو الحال دائمًا:

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

irb> t = T.new
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf">

irb> t.instance_method
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> nil

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

ال @@class_variable و @instance_variable تصرف دائمًا كما تتوقع:يتم تعريف الأول على مستوى الفصل، وسواء تمت الإشارة إليه في أسلوب الفصل أو في أسلوب المثيل، فإنه يحمل القيمة المخصصة له في الأعلى.هذا الأخير يحصل فقط على قيمة في كائن من الفئة T, ، لذلك في طريقة الفصل، يشير إلى متغير غير معروف قيمته nil.

تم تسمية طريقة الفصل بشكل خيالي class_method إخراج قيم @@class_variable واثنين @class_instance_variableكما هو متوقع، أي كما تمت تهيئته في أعلى الفصل الدراسي.ومع ذلك، في أساليب المثال initialize و instance_method, مختلف المتغيرات من نفس الاسم يتم الوصول إليها، أي متغيرات المثيل، وليس متغيرات مثيل الفئة.

يمكنك أن ترى أن المهمة في initialize لم تؤثر الطريقة على متغير مثيل الفئة @class_instance_variable_1, ، لأن الدعوة في وقت لاحق من class_method يخرج قيمته القديمة ، "WTF".بدلا من ذلك، الأسلوب initialize تم الإعلان عن متغير مثيل جديد، واحد وهو أيضًا اسمه (مضلل) @class_instance_variable_1.القيمة المخصصة له، "wtf", ، يتم الإخراج بالطرق initialize و instance_method.

المتغير @class_instance_variable_2 في رمز المثال يعادل المتغير @hello في المشكلة الأصلية:تم الإعلان عنه وتهيئته كمتغير مثيل للفئة، ولكن عندما تشير طريقة المثيل إلى متغير بهذا الاسم، فإنه يرى فعليًا متغير مثيل بنفس الاسم - لم يتم التصريح عنها مطلقًا، فقيمتها صفر.

وأوصى أيضا النظر في المتغيرات الطبقة التي تكون مسبوقة مع "" - وهنا بعض التعليمات البرمجية لتبين لكم كيف الفئة و المثيل فار مختلفة:

class Vars
  @@classvar="foo"
  def test
    @instancevar="bar"
  end
  def Vars.show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"
  end
  def instance_show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"

  end
end

# only shows classvar since we don't have an instance created
Vars::show
# create a class instance
vars = Vars.new
# instancevar still doesn't show b/c it hasn't been initialized
vars.instance_show
# initialize instancevar
vars.test
# now instancevar shows up as we expect
vars.instance_show
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top