שלום אורח התחבר

משתנים ופונקציות גלובאליים ברובי

נושאים:יומי

רובי מבדילה בין משתנים שהם מקומיים לקובץ לבין פונקציות שהן גלובאליות ואפשר להפעיל אותן גם מקבצים אחרים - אבל האופן בו הבדל זה מיושם הוא מעניין ושונה משפות רבות אחרות שפגשתי. בואו ניקח טיול קצר ברובי כדי לראות הבדל זה.

1הגדרת משתנים ופונקציות באותו קובץ

נגדיר קובץ בשם utils.rb עם התוכן הבא:

def twice(x)
    x * 2
end

value = 10

יש לנו פונקציה ומשתנה פרטי. עכשיו אפשר לעבור ל irb כדי לראות את ההבדל ביניהם כשמנסים לטעון את הקובץ ממקום אחר.

2איך פונקציות ומשתנים נראים מבחוץ

נתחיל עם המשתנה הפרטי - טעינת הקובץ וניסיון לגשת למשתנה נכשלת:

> require './utils.rb'
> value
Traceback (most recent call last):
        4: from /Users/ynonperek/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `<main>'
        3: from /Users/ynonperek/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `load'
        2: from /Users/ynonperek/.rvm/rubies/ruby-2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        1: from (irb):2
NameError (undefined local variable or method `value' for main:Object)

זה הגיוני אבל ההודעה קצת מפתיעה: לא מוגדר משתנה מקומי בשם value וגם לא מוגדרת מתודה על Object בשם זה. החלק השני רומז להתנהגות כשניגש לפונקציה.

 > require './utils.rb'
 > twice(10)
  => 20

וזה הצליח! אבל רגע, מה לגבי ההודעה ההיא עם המתודה של Object? נסתכל רגע על האוביקט:

> Object.private_instance_methods
 => [:DelegateClass, :twice, :irb_binding, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :srand, :warn, :local_variables, :trap, :abort, :require, :rand, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :binding, :require_relative, :autoload, :autoload?, :eval, :iterator?, :block_given?, :catch, :throw, :loop, :system, :spawn, :exec, :exit!, :trace_var, :untrace_var, :at_exit, :select, :`, :Rational, :gem_original_require, :Complex, :set_trace_func, :pp, :gem, :respond_to_missing?, :test, :caller_locations, :caller, :fork, :exit, :gets, :proc, :lambda, :initialize_copy, :initialize_clone, :initialize_dup, :URI, :sleep, :load, :syscall, :open, :printf, :print, :putc, :puts, :readline, :readlines, :p, :singleton_method_added, :method_missing, :singleton_method_removed, :singleton_method_undefined, :initialize] 

וכבר הפונקציה השניה ברשימה נראית מוכרת! זו twice שלנו. הפונקציה הגלובלית היא בעצם מתודה פרטית של האוביקט Object. תופעת לוואי מעניינת של מבנה זה היא שעכשיו אפשר להפעיל פונקציה זו דרך כל אוביקט רובי. הנה המשך העבודה מ irb:

> l = [10, 20, 30]
 => [10, 20, 30] 
 > l.send(:twice, 10)
  => 20 

חיפוש שם של משתנה או פונקציה ברובי מתחיל בחיפוש משתנה מקומי בשם שכתבנו וממשיך בחיפוש מתודה בשם זה בתוך ה Scope הנוכחי, ומשם ממשיכים לחפש במעלה ה Scope Chain עד שמגיעים ל Object. בתוך מגבלה זו של השפה הדרך היחידה של פונקציה להיות "גלובאלית" היא להישתל בתור מתודה של Object, כך שמכל אוביקט אפשר יהיה להפעיל אותה.

מעדיפים לקרוא מהטלגרם? בקרו אותנו ב:@tocodeil

או הזינו את כתובת המייל וקבלו את הפוסט היומי בכל בוקר אליכם לתיבה:


נהניתם מהפוסט? מוזמנים לשתף ולהגיב