Необязательные параметры Ruby - PullRequest
120 голосов
/ 01 мая 2009

Если я определю функции Ruby следующим образом:

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

Как я могу назвать это, поставляя только первые 2 и последние аргументы? Почему не что-то вроде

ldap_get( base_dn, filter, , X)

возможно или, если возможно, как это можно сделать?

Ответы [ 8 ]

136 голосов
/ 01 мая 2009

Вам почти всегда лучше использовать хэш опций.

def ldap_get(base_dn, filter, options = {})
  options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE
  ...
end

ldap_get(base_dn, filter, :attrs => X)
130 голосов
/ 01 мая 2009

Это не возможно с рубином в настоящее время. Вы не можете передавать «пустые» атрибуты в методы. Самое близкое, что вы можете получить, это передать nil:

ldap_get(base_dn, filter, nil, X)

Однако, это установит область действия на ноль, а не LDAP :: LDAP_SCOPE_SUBTREE.

Что вы можете сделать, это установить значение по умолчанию в вашем методе:

def ldap_get(base_dn, filter, scope = nil, attrs = nil)
  scope ||= LDAP::LDAP_SCOPE_SUBTREE
  ... do something ...
end

Теперь, если вы вызовете метод, как описано выше, поведение будет таким, как вы ожидаете.

51 голосов
/ 14 июля 2014

Время шло, и начиная с версии 2 Ruby поддерживает именованные параметры:

def ldap_get ( base_dn, filter, scope: "some_scope", attrs: nil )
  p attrs
end

ldap_get("first_arg", "second_arg", attrs: "attr1, attr2") # => "attr1, attr2"
3 голосов
/ 01 мая 2009

Невозможно сделать это так, как вы определили ldap_get. Тем не менее, если вы определите ldap_get следующим образом:

def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE )

Теперь вы можете:

ldap_get( base_dn, filter, X )

Но теперь у вас есть проблема, которую вы не можете вызвать с помощью первых двух аргументов и последнего аргумента (та же проблема, что и раньше, но теперь последний аргумент отличается).

Объяснение этого простое: каждый аргумент в Ruby не обязательно должен иметь значение по умолчанию, поэтому вы не можете назвать его так, как вы указали. Например, в вашем случае первые два аргумента не имеют значений по умолчанию.

1 голос
/ 12 марта 2014

1) Вы не можете перегрузить метод ( Почему ruby ​​не поддерживает перегрузку метода? ), так почему бы вообще не написать новый метод?

2) Я решил аналогичную проблему, используя оператор splat * для массива нулевой или более длины. Затем, если я хочу передать параметр (параметры), который я могу, он интерпретируется как массив, но если я хочу вызвать метод без какого-либо параметра, мне не нужно ничего передавать. См. Язык программирования Ruby , страницы 186/187

0 голосов
/ 09 марта 2016

Вы можете сделать это с частичным применением, хотя использование именованных переменных определенно приводит к более читабельному коду. Джон Резиг написал статью в блоге в 2008 году о том, как сделать это на JavaScript: http://ejohn.org/blog/partial-functions-in-javascript/

Function.prototype.partial = function(){
  var fn = this, args = Array.prototype.slice.call(arguments);
  return function(){
    var arg = 0;
    for ( var i = 0; i < args.length && arg < arguments.length; i++ )
      if ( args[i] === undefined )
        args[i] = arguments[arg++];
    return fn.apply(this, args);
  };
};

Вероятно, было бы возможно применить тот же принцип в Ruby (за исключением наследования прототипа).

0 голосов
/ 28 января 2014

Недавно я нашел способ обойти это. Я хотел создать метод в классе массива с необязательным параметром, чтобы сохранить или отбросить элементы в массиве.

Я смоделировал это, передав массив в качестве параметра и проверив, равняется ли значение этого индекса нулю или нет.

class Array
  def ascii_to_text(params)
    param_len = params.length
    if param_len > 3 or param_len < 2 then raise "Invalid number of arguments #{param_len} for 2 || 3." end
    bottom  = params[0]
    top     = params[1]
    keep    = params[2]
    if keep.nil? == false
      if keep == 1
        self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
      else
        raise "Invalid option #{keep} at argument position 3 in #{p params}, must be 1 or nil"
      end
    else
      self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
    end
  end
end

Испытание нашего метода класса с различными параметрами:

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126, 1]) # Convert all ASCII values of 32-126 to their chr value otherwise keep it the same (That's what the optional 1 is for)

вывод: ["1", "2", "a", "b", "c"]

Хорошо, круто, что работает, как и планировалось. Теперь давайте проверим и посмотрим, что произойдет, если мы не передадим третий параметр option (1) в массиве.

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126]) # Convert all ASCII values of 32-126 to their chr value else remove it (1 isn't a parameter option)

вывод: ["a", "b", "c"]

Как видите, третья опция в массиве была удалена, что инициировало другой раздел метода и удалило все значения ASCII, которые не входят в наш диапазон (32-126)

В качестве альтернативы, мы могли бы выдать значение как nil в параметрах. Который будет выглядеть как следующий блок кода:

def ascii_to_text(top, bottom, keep = nil)
  if keep.nil?
    self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
  else
    self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
end
0 голосов
/ 09 ноября 2010

можно :) Просто измените определение

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

до

def ldap_get ( base_dn, filter, *param_array, attrs=nil )
scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE

область будет теперь в массиве на его первом месте. Когда вы предоставите 3 аргумента, вам будут назначены base_dn, filter и attrs, а param_array будет [] Когда 4 и более аргументов, тогда param_array будет [аргумент1, или_больше, и_морей]

Недостатком является ... это неясное решение, действительно безобразное. Это ответ на вопрос, что можно опустить аргумент в середине вызова функции в ruby:)

Еще одна вещь, которую вы должны сделать, это переписать значение области по умолчанию.

...