首頁  >  問答  >  主體

ruby -- 全局和局部问题

n = 5
def num
  puts n
end

为什么是错的的?
我知道全局和局部基本原理。
局部变量在函数里只能使用,在外部是不存在。

但是在python或js里使用这样方式可以执行的!
还是只有ruby要在函数使用变量需要重新宣告。

请问各位可以解释吗?
谢谢

黄舟黄舟2761 天前753

全部回覆(6)我來回復

  • 黄舟

    黄舟2017-04-22 09:01:49

    def 是開啟了一個新的作用域

    n = 5
    local_variables       # => [:n, :_]
    def num
      local_variables     # => []
    end
    

    如果你要訪問 n,需要用扁平化作用域

    define_method :num do
        puts n
    end
    

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-22 09:01:49

    @n = 5
    def num
        puts @n
    end
    

    我也是初學者,看看其它高手怎麼說。

    回覆
    0
  • 迷茫

    迷茫2017-04-22 09:01:49

    但是在python或js裡使用這樣方式可以執行的!

    Python 中是唯讀


    以下是猜想為什麼 Ruby 要這麼搞?

    Ruby 中 def 生成的方法只能访问全局变量。
    define_method 生成的方法 和 -> (param) {}lambda { |param| } 產生的 proc 帶閉包,可以存取外層變數。

    我猜想是因為 Ruby 認為最常用的情況是你不需要訪問外層變量,所以 def 不給你訪問了,這樣的好處:

    • 不會像 js 一樣無意中搞亂外層變數。 JavaScript 為了避免這一點,都要在 function 頭部把體內用到的變數都 undefined 一下,很囉嗦。
    • 不用建立閉包,節省開銷。

    至於 lambda 帶閉包那很正常,都 lambda 了不帶閉包說的過去嗎?

    至於 define_method,猜想是因為

    • define_method 因為是所謂元編程,有更大機率用外層變量,(本來用元編程就是偷懶少打字,要是不能用外層變量,還要作為參數傳入,那累死了。)所以就帶閉包。
    • method 定義不能帶閉包有時候會不方便,但是通常也不需要,所以就讓長一點的 define_method 帶閉包囉。
    • define_method 除了 define_method (symbol) { |param| },还可以写成 define_method(symbol, method),其中 method 比较常用的就是传入一个 lambda,既然传入 lambda,如果本身 define_method 除了define_method (symbol) { |param| },還可以寫成define_method(symbol, method),其中method 比較常用的是傳入一個lambda,既然傳入lambda,如果本身
    • 不帶閉包,那就會很違和的說,所以就讓它帶囉。
    🎜

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-22 09:01:49

    @Andrew_375683 說的是正確的.
    主要是作用域的問題
    不過這裡還有個簡單的方法解決將n變成函數就可以了

    def n
      5
    end
    
    def num
      p n
    end
    
    num
    

    回覆
    0
  • 巴扎黑

    巴扎黑2017-04-22 09:01:49

    這問題火啊。剛去趟,回來就幾人回答了。

    你的程式碼中的n,你以為是全域變量,可惜不是

    irb(main):006:0> x =10
    => 10
    irb(main):009:0> defined? x
    => "local-variable"
    

    需要修改就是加個$作為前綴即可:

    irb(main):010:0> $x = 1
    => 1
    irb(main):011:0> defined? $x
    => "global-variable"
    

    在美好的ruby 風格中 ,$是多麼扎眼啊。 ruby老闆知道全域變數不可缺,但也怕濫用,因此玩了一個小把戲;)。涉及到的是ruby variables scope 的知識,ruby的優點複雜也與眾不同。

    @andrewzhyl 說的不錯,按讚。

    回覆
    0
  • 高洛峰

    高洛峰2017-04-22 09:01:49

    做個筆記:def與def_method的區別:def是用來定義方法的關鍵字;def_method是一個方法,它的作用是產生一個新方法,def中的代碼跟上下文完全隔離的(只認識帶@跟美刀的變數);而define_method就顯得更open一點,樂意認識不帶任何修飾的夥伴。

    回覆
    0
  • 取消回覆