Рубі додаткові параметри


121

Якщо я визначаю такі функції Ruby:

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

Як я можу назвати, що вона постачає лише перші 2 та останні аргументи? Чому це не щось на кшталт

ldap_get( base_dn, filter, , X)

можливо, або якщо це можливо, як це можна зробити?

Відповіді:


131

Наразі це неможливо з рубіном. Ви не можете передавати "порожні" атрибути методам. Найближче, що можна отримати, - це пройти нуль:

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

Тепер, якщо ви будете називати метод як вище, поведінка буде такою, як ви очікували.


21
Невелика проблема з цим методом: наприклад, якщо ви намагаєтесь зробити значення за замовчуванням scopeсправжнім і перейдете false, scope ||= trueне вийде. Він оцінює те саме, що nilі встановить йогоtrue
Джошуа Пінтер

4
чи можливо з поточною версією рубіну через 3 роки після цієї відповіді?
dalloliogm

1
@JoshPinter, приємне пояснення. В основному || = не a = b або c, я притиснувся, побачивши xyz||=true. Це означає, що якщо це нуль, це завжди правда. Якщо це правда, то це правда.
Деймон Ав

7
Коли всі кажуть, як це погано scope ||= true, я здивований, що ніхто не згадав, що кращий спосіб зробити це scope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?. Звичайно, навіть це припущення, що nilце недійсне значення.
Ерік Сандберг

1
Оновлення до цієї старої: Альтернативою є використання позначень підкреслення. На жаль, це має такий же ефект, як і встановлення параметра nil. Деяким може сподобатися позначення: ldap_get(base_dn, filter, _, X)(зауважте: я не знаю (поки), коли це було введено в Ruby. Цікава тема потоку ).
Ерік Платон

137

Вам майже завжди краще використовувати хеш-параметри.

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

ldap_get(base_dn, filter, :attrs => X)

23
Загальна стратегія полягає в тому, щоб мати хеш-параметри за замовчуванням і об'єднати все, що було передано:options = default_options.merge(options)
Натан Лонг

7
Я перешкоджаю цьому, оскільки параметри не говорять вам про те, що очікує метод, або які значення за замовчуванням
Bron Davies

53

Час пішов і з версії 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"

1
Ви також можете використовувати подвійний штрих для збору додаткових невизначених аргументів ключових слів. Це пов’язано з цим питанням: stackoverflow.com/a/35259850/160363
Генрі Ценг

3

Це неможливо зробити так, як ви визначили 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

1) Ви не можете перевантажувати метод ( чому не перевантажує метод підтримки рубіну? ), Так чому б взагалі не написати новий метод?

2) Я вирішив подібну проблему, використовуючи оператор splat * для масиву нульової або більшої довжини. Потім, якщо я хочу передати параметр (и), який я можу, він трактується як масив, але якщо я хочу викликати метод без жодного параметра, то мені нічого не потрібно передавати. Див. Сторінки мови програмування Ruby 186/187


0

Нещодавно я знайшов шлях до цього. Я хотів створити метод у класі масиву з необов'язковим параметром, щоб зберегти або відкинути елементи в масиві.

Я моделював це шляхом передачі масиву як параметра, а потім перевірки, чи значення цього індексу було нульовим чи ні.

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"]

Гаразд, круто, що працює за планом. Тепер перевіримо і подивимося, що станеться, якщо ми не перейдемо до третього параметра параметра (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)

Крім того, ми могли б видати значення як нульове значення в параметрах. Що буде схоже на наступний блок коду:

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

-1

Можливо :) Просто змініть визначення

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 буде [argument1, or_more, and_more]

Нижня частина - це незрозуміле рішення, насправді потворне. Це відповідь, що можна опустити аргумент посеред виклику функції в рубіні :)

Ще одна річ, яку ви повинні зробити, це переписати значення за замовчуванням на область застосування.


4
Це рішення абсолютно неправильно. Синтаксична помилка використовувати параметр значення за замовчуванням ( attrs=nil) після splat ( *param_array).
Ерік Сандберг

3
-1: Ерік правильний. Викликає синтаксичну помилку в irb 2.0.0p247. Згідно з мовою програмування Ruby , у Ruby 1.8 параметр splat повинен був бути останнім, окрім an &parameter, але в Ruby 1.9 за ним можуть також слідувати "звичайні параметри". В жодному випадку не було параметра з легальним за замовчуванням параметром після параметра із знаком splat.
andyg0808

Сторінка 186/187 Ruby Language програмування. Він повинен бути останнім параметром у методі, якщо & не використовується.
rupweb

Отже, AndyG має рацію, порядок має бути таким: def ldap_get (base_dn, filter, attrs = nil, * param_array)
rupweb

-1

Це можна зробити за допомогою часткового застосування, хоча використання названих змінних безумовно призводить до більш читабельного коду. Джон Ресіг написав статтю в блозі про 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);
  };
};

Можливо, було б можливо застосувати той же принцип у Рубі (за винятком прототипічного успадкування).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.