代码之家  ›  专栏  ›  技术社区  ›  Bobby B

Ruby的*args在没有提供args时导致seg错误

  •  1
  • Bobby B  · 技术社区  · 15 年前

    我正在尝试使用Ruby在Windows中进行一些脚本GUI测试。我在利用 pragprog book 我遇到了点麻烦。我已经分解出一些代码来帮助win32api函数的重复映射。代码如下:

    module WindowsGui
    
      def self.def_api(function, parameters, return_value)              
        api = Win32API.new 'user32', function, parameters, return_value
    
        define_method(function.snake_case) do |*args|                  
          api.call *args                                                
        end
    
      end
    end
    

    …因此我可以使用该块以以下方式在模块中定义几个Win32API:

    def_api 'FindWindow', ['P', 'P'], 'L' 
    

    我有一些RSpec测试,以确保它的行为,因为它应该。

      it 'wraps a Windows call with a method' do
        find_window(nil, nil).should_not == 0
      end
      
      it 'enforces the argument count' do
        lambda {find_window}.should raise_error
      end
    

    第一次测试一切正常,第二次测试导致seg故障。似乎如果我不使用args来调用这个,我不能触摸*args-但是我可以做一个args.length来查看它是空的。

    为什么这会导致seg故障而不是异常?我们可以通过这样的方式来解决这个问题吗。。

      raise BadArgs if args.length == 0
    

    还有一个太长的问题-抱歉。

    蒂亚! 鲍勃

    1 回复  |  直到 5 年前
        1
  •  1
  •   bjg    15 年前

    可能的原因是因为下面的某个地方 Win32API 缺少参数将转换为一个或多个空指针取消引用。

    如果要创建这样的函数,那么应该考虑添加一个per-api调用、返回参数验证块(或lambda)的布尔函数作为 def_api 然后将其作为派生函数的第一部分调用。像这样:

    def self.def_api(function, parameters, return_value, &valid_args?)              
      api = Win32API.new 'user32', function, parameters, return_value
    
      define_method(function.snake_case) do |*args|
        if valid_args? and valid_args?.call(*args)               
          api.call *args
        else
          // raise argument error, etc
        end                                         
      end
    
    end
    

    那么

    def_api 'FindWindow', ['P', 'P'], 'L', { |args| return true if // API specific checks succeed }
    

    这个 &valid_args? 是块参数的名称。与号前缀(&)就是你告诉鲁比你经过一个街区。只能将一个块传递给method,并且它必须是参数列表中的最后一个参数。问号后缀(?)只是Ruby编程中用于命名返回布尔值的函数的约定。

    &block.call(args)

    要使用块参数调用方法,请执行以下操作:

    method { |args| // block implementation }
    

    method do |args|
      // block implementation
    end
    

    这个 args call method . 希望这有帮助。