Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 传递散列而不是方法参数_Ruby_Oop_Coding Style - Fatal编程技术网

Ruby 传递散列而不是方法参数

Ruby 传递散列而不是方法参数,ruby,oop,coding-style,Ruby,Oop,Coding Style,我看到在Ruby(通常是动态类型语言)中,一种非常常见的做法是传递散列,而不是声明具体的方法参数。例如,与其声明带有参数的方法并像这样调用它,不如: def my_method(width, height, show_border) my_method(400, 50, false) 您可以这样做: def my_method(options) my_method({"width" => 400, "height" => 50, "show_border" => false}

我看到在Ruby(通常是动态类型语言)中,一种非常常见的做法是传递散列,而不是声明具体的方法参数。例如,与其声明带有参数的方法并像这样调用它,不如:

def my_method(width, height, show_border)
my_method(400, 50, false)
您可以这样做:

def my_method(options)
my_method({"width" => 400, "height" => 50, "show_border" => false})

我想知道你对这件事的看法。这是一个好的做法还是一个坏的做法,我们应该做还是不做?在什么情况下使用这种做法是有效的,在什么情况下可能是危险的?

这是一种良好的做法。您不需要考虑方法签名和参数的顺序。另一个优点是,您可以很容易地忽略不想输入的参数。
您可以看看ExtJS框架,因为它广泛使用这种类型的参数传递。

我认为当有多个参数或多个可选参数时,这种参数传递方法更为清晰。它本质上使方法调用明显地自文档化。

在Ruby中,使用哈希而不是形式参数是不常见的做法。

我认为这与将散列作为参数传递的常见模式相混淆,因为该参数可以接受许多值,例如在GUI工具包中设置窗口的属性

如果方法或函数有许多参数,则显式声明并传递它们。您得到的好处是,解释器将检查您是否已传递了所有参数


不要滥用语言功能,知道什么时候使用它,什么时候不使用它。

Ruby有隐式散列参数,所以您也可以编写

def my_method(options = {}) 

my_method(:width => 400, :height => 50, :show_border => false)
通过Ruby 1.9和新的哈希语法,它可以

my_method( width: 400, height: 50, show_border: false )

当一个函数包含3-4个以上的参数时,不计算相应的位置,就很容易看出哪个是什么。

这是一种折衷。您失去了一些清晰性(我如何知道要传递什么参数)和检查(我传递了正确数量的参数吗?)并获得了灵活性(该方法可以默认它没有接收到的参数,我们可以部署一个新版本,使用更多参数,并且不破坏现有代码)

您可以将此问题视为更大的强/弱类型讨论的一部分。请看这里的博客。我在C和C++中使用了这种风格,在这里我想支持相当灵活的参数传递。可以说,带有一些查询参数的标准HTTP GET正是这种风格


如果您选择hash appraoch,我会说您需要确保您的测试非常好,参数名称拼写错误的问题只会在运行时出现。

这两种方法都有各自的优点和缺点,当使用选项散列替换标准参数时,定义方法的代码将变得不清晰,但每当使用该方法时,就会变得清晰,因为使用选项散列创建的伪命名参数


我的一般规则是,如果一个方法有很多参数(超过3个或4个),或者有很多可选参数,那么就使用选项散列,否则就使用标准参数。但是,在使用选项哈希时,务必在方法定义中包含一条注释,说明可能的参数。

如果您:

  • 具有6个以上的方法参数
  • 传递具有一些必需、一些可选和一些默认值的选项
  • 您很可能希望使用散列。不用查阅文档,就可以更容易地了解参数的含义

    对于那些说很难弄清楚一个方法采用了什么选项的人来说,这仅仅意味着代码的文档记录很差。使用,您可以使用
    @选项
    标记指定选项:

    ##
    # Create a box.
    #
    # @param [Hash] options The options hash.
    # @option options [Numeric] :width The width of the box.
    # @option options [Numeric] :height The height of the box.
    # @option options [Boolean] :show_border (false) Whether to show a
    #   border or not.
    def create_box(options={})
      options[:show_border] ||= false
    end
    
    但在这个具体的例子中,参数非常少且简单,所以我想我应该这样做:

    ##
    # Create a box.
    #
    # @param [Numeric] width The width of the box.
    # @param [Numeric] height The height of the box.
    # @param [Boolean] show_border Whether to show a border or not.
    def create_box(width, height, show_border=false)
    end
    

    我确信没有人使用动态语言关心这个问题,但是想想当你开始向函数传递散列时,你的程序将会受到的性能损失

    解释器可能足够聪明,可以创建一个静态常量散列对象,并且只通过指针引用它,如果代码使用的是散列,所有成员都是源代码文本

    但是,如果这些成员中有任何一个是变量,那么每次调用哈希时都必须重新构造它

    我已经做了一些Perl优化,这种事情在内部代码循环中变得很明显


    函数参数的性能要好得多。

    使用
    散列作为参数的好处在于消除了对参数数量和顺序的依赖

    实际上,这意味着您以后可以灵活地重构/更改方法,而不会破坏与客户机代码的兼容性(这在构建库时非常好,因为您实际上无法更改客户机代码)


    (如果你对Ruby中的软件设计感兴趣,Sandy Metz是一本很棒的书)

    一般来说,我们应该始终使用标准参数,除非这是不可能的。在不必使用选项的情况下使用选项是不好的做法。标准参数是清晰的,并且是自我记录的(如果命名正确的话)

    使用选项的一个(可能也是唯一的)原因是函数接收的参数不进行处理,而只是传递给另一个函数

    下面是一个例子,说明:

    def myfactory(otype, *args)
      if otype == "obj1"
        myobj1(*args)
      elsif otype == "obj2"
        myobj2(*args)
      else
        puts("unknown object")
      end
    end
    
    def myobj1(arg11)
      puts("this is myobj1 #{arg11}")
    end
    
    def myobj2(arg21, arg22)
      puts("this is myobj2 #{arg21} #{arg22}")
    end
    

    在本例中,“myfactory”甚至不知道“myobj1”或“myobj2”所需的参数myfactory只将参数传递给“myobj1”和“myobj2”,检查和处理它们是它们的责任。

    哈希对于传递多个可选参数特别有用。例如,我使用散列来初始化参数为可选的类

    例子
    如果您需要可变数量的参数,只需使用
    def method(*args)
    ,散列无法解决特定的问题感谢您指出了潜在的混淆。我真的在想这个案子
    class Example
    
    def initialize(args = {})
    
      @code
    
      code = args[:code] # No error but you have no control of the variable initialization. the default value is supplied by Hash
    
      @code = args.fetch(:code) # returns IndexError exception if the argument wasn't passed. And the program stops
    
      # Handling the execption
    
      begin
    
         @code = args.fetch(:code)
    
      rescue 
    
     @code = 0
    
      end
    
    end