IT박스

메소드 매개 변수 대신 해시 전달

itboxs 2020. 10. 15. 07:38
반응형

메소드 매개 변수 대신 해시 전달


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})

그것에 대한 당신의 의견을 알고 싶습니다. 좋은 습관입니까, 나쁜 습관입니까? 이 관행을 사용하는 것이 어떤 상황에서 타당하며 어떤 상황에서 위험 할 수 있습니까?


두 방법 모두 고유 한 장점과 단점이 있습니다. 표준 인수를 대체하는 옵션 해시를 사용하면 메서드를 정의하는 코드에서 명확성을 잃지 만 옵션 해시를 사용하여 생성 된 의사 이름 매개 변수로 인해 메서드를 사용할 때마다 명확성을 얻습니다.

내 일반적인 규칙은 메서드에 대한 인수가 많거나 (3 개 또는 4 개 이상) 선택적 인수가 많은 경우 옵션 해시를 사용하고 그렇지 않으면 표준 인수를 사용하는 것입니다. 그러나 옵션 해시를 사용할 때 가능한 인수를 설명하는 메서드 정의에 항상 주석을 포함하는 것이 중요합니다.


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 개 이상의 매개 변수를 사용하는 경우 각 위치를 계산하지 않고도 어떤 것이 무엇인지 쉽게 알 수 있습니다.


다음 중 하나라면 말하고 싶습니다.

  1. 6 개 이상의 메서드 매개 변수가 있음
  2. 일부는 필수, 일부는 선택 사항, 일부는 기본값이있는 전달 옵션

아마도 해시를 사용하고 싶을 것입니다. 문서에서 찾아 보지 않고도 인수가 의미하는 바를 확인하는 것이 훨씬 쉽습니다.

메소드가 어떤 옵션을 사용하는지 파악하기 어렵다고 말하는 사람들에게는 코드가 제대로 문서화되지 않았다는 의미입니다. YARD , 당신은 사용할 수있는 @option옵션을 지정 태그 :

##
# 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

이 매개 변수 전달 방법은 매개 변수가 두 개 이상이거나 선택적 매개 변수가 많을 때 훨씬 더 명확하다고 생각합니다. 본질적으로 메서드 호출을 명백하게 자체 문서화합니다.


루비에서는 형식 매개 변수가 아닌 해시를 사용하는 것이 일반적이지 않습니다.

매개 변수가 GUI 툴킷에서 창 속성을 설정하는 등 여러 값을 취할 수있을 때 해시를 매개 변수로 전달하는 일반적인 패턴과 혼동되는같습니다 .

메서드 또는 함수에 여러 인수가있는 경우 명시 적으로 선언하고 전달합니다. 통역사가 모든 인수를 통과했는지 확인하는 이점이 있습니다.

언어 기능을 남용하지 말고 사용시기와 사용하지 않아야 할시기를 알고 있어야합니다.


Hashas 매개 변수 사용의 이점 은 인수의 수와 순서에 대한 종속성을 제거한다는 것입니다.

실제로 이것은 나중에 클라이언트 코드와의 호환성을 깨지 않고 메서드를 리팩터링 / 변경할 수있는 유연성을 갖게됨을 의미합니다 (실제로 클라이언트 코드를 변경할 수 없기 때문에 라이브러리를 빌드 할 때 매우 좋습니다).

(Sandy Metz의 "Practical Object-Oriented Design in Ruby"Ruby의 소프트웨어 디자인에 관심이 있다면 훌륭한 책입니다.)


좋은 습관입니다. 메서드 시그니처와 인수 순서에 대해 생각할 필요가 없습니다. 또 다른 장점은 입력하고 싶지 않은 인수를 쉽게 생략 할 수 있다는 것입니다. 광범위하게 전달되는 이러한 유형의 인수를 사용하므로 ExtJS 프레임 워크를 살펴볼 수 있습니다.


It's a trade-off. You lose some clarity (how do I know what params to pass) and checking (did I pass the right number of arguments?) and gain flexibility (the method can default params it doesn't receive, we can deploy a new version that takes more params and break no existing code)

You can see this question as part of the larger Strong/Weak type discussion. See Steve yegge's blog here. I've used this style in C and C++ in cases where I wanted to support quite flexible argument passing. Arguably a standard HTTP GET, with some query parameters is exactly this style.

If you go for the hash appraoch I'd say that you need to make sure your testing is really good, problems with incorrectly spelled parameter names will only show up at run time.


I'm sure no one using dynamic languages cares, but think about the performance penalty your program is going to be hit with when you start passing hashes to functions.

The interpreter may possibly be smart enough to create a static const hash object and only reference it by pointer, if the code is using a hash with all members that are source code literals.

But if any of those members are variables then the hash must be reconstructed each time it is called.

I've done some Perl optimizations and this kind of thing can become noticeable in inner code loops.

Function parameters perform much better.


In general we should always use standard arguments, unless it's not possible. Using options when you do not have to use them is bad practice. Standard arguments are clear and self-documented (if properly named).

One (and maybe the only) reason to use options is if function receives arguments which does not process but just pass to another function.

Here is an example, that illustrates that:

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

In this case 'myfactory' is not even aware of the arguments required by the 'myobj1' or 'myobj2'. 'myfactory' just passes the arguments to the 'myobj1' and 'myobj2' and it's their responsibility to check and process them.


Hashes are particularly useful to pass multiple optional arguments. I use hash, for example to initialize a class whose arguments are optional.

EXAMPLE

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

참고URL : https://stackoverflow.com/questions/1927291/passing-hashes-instead-of-method-parameters

반응형