Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby 메서드 조회 이해하기

메소드를 호출하면 어떻게 됩니까? 같은 이름을 가진 다른 메서드가 있을 때 Ruby는 어떤 메서드를 호출할지 어떻게 결정합니까? 분석법이 어디에 보관되거나 출처가 어디인지 궁금하신가요?

Ruby는 정의된 "way" 또는 "pattern"을 사용하여 호출할 올바른 메서드와 "no method error"를 반환할 적절한 시간을 결정하며 이 "way"를 Ruby 메서드 조회 경로 .이 튜토리얼에서는 Ruby의 메소드 조회에 대해 알아보겠습니다. 마지막에는 Ruby가 개체의 계층 구조를 통해 참조하는 메서드를 결정하는 방법을 잘 이해하게 될 것입니다.

우리가 배울 내용을 완전히 이해하려면 Ruby에 대한 기본적인 이해가 필요합니다. 모듈 및 클래스와 같은 항목에 대해 언급할 것이지만 이것이 수행하는 작업에 대해 자세히 설명하지는 않습니다. 이 튜토리얼의 목표에 도달하는 데 필요한 깊이만 다룰 것입니다. Ruby가 객체에 전달할 메시지(메소드)를 어떻게 결정하는지 보여줍니다.

개요

first_person.valid?와 같은 메소드를 호출할 때 , Ruby는 몇 가지 사항을 결정해야 합니다.

  1. .valid? 정의됩니다.
  2. .valid? 방법이 정의되어 있습니까? 그렇다면 이 맥락에서 사용하기에 적합한 것입니다.

Ruby가 이를 알아내기 위해 따르는 프로세스(또는 경로)는 우리가 메서드 조회라고 부르는 것입니다. . Ruby는 메서드를 호출할 수 있도록 메서드가 생성된 위치를 찾아야 합니다. 올바른 메서드를 호출하는지 확인하려면 다음 위치에서 검색해야 합니다.

  1. 싱글톤 메소드:Ruby는 객체가 자체 메소드를 정의할 수 있는 방법을 제공합니다. 이러한 메서드는 해당 개체에만 사용할 수 있으며 개체의 인스턴스에서 액세스할 수 없습니다.
  2. 혼합 모듈의 메서드:prepend를 사용하여 모듈을 클래스에 혼합할 수 있습니다. , include 또는 extend . 이 경우 클래스는 모듈에 정의된 메서드에 액세스할 수 있으며 Ruby는 모듈로 이동하여 호출된 메서드를 검색합니다. 다른 모듈을 초기 모듈에 혼합할 수 있으며 검색도 이러한 모듈로 진행된다는 사실을 아는 것도 중요합니다.
  3. 인스턴스 메소드:클래스에 정의되어 있으며 해당 클래스의 인스턴스에서 액세스할 수 있는 메소드입니다.
  4. 상위 클래스 메소드 또는 모듈:클래스가 다른 클래스의 자식인 경우 Ruby는 상위 클래스에서 검색합니다. 검색은 상위 클래스 싱글톤 메서드, 혼합 모듈 및 상위 클래스로 이동합니다.
  5. Object, Kernel 및 BasicObject:Ruby가 검색하는 마지막 위치입니다. Ruby의 모든 객체는 이러한 객체를 조상의 일부로 가지고 있기 때문입니다.

클래스 및 모듈

메서드는 종종 개체에 대해 호출됩니다. 이러한 객체는 Ruby의 내장 클래스 또는 개발자가 만든 클래스일 수 있는 특정 클래스에 의해 생성됩니다.

class Human
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def hello
    put "Hello! #{name}"
  end
end

그런 다음 hello를 호출할 수 있습니다. Human 인스턴스에 대해 위에서 만든 메서드 수업; 예를 들어,

john = Human.new("John")
john.hello # Output -> Hello John

hello 메소드는 인스턴스 메소드입니다. 이것이 Human 인스턴스에서 호출할 수 있는 이유입니다. 수업. 인스턴스에서 메서드가 호출되는 것을 원하지 않는 경우가 있을 수 있습니다. 이 경우 클래스 자체에서 메서드를 호출하려고 합니다. 이를 달성하려면 클래스 메서드를 만들어야 합니다. 위에 있는 클래스에 대한 클래스 메서드를 정의하면 다음과 같습니다.

  def self.me
    puts "I am a class method"
  end

그런 다음 Human.me를 수행하여 이것을 호출할 수 있습니다. . 애플리케이션의 복잡성이 증가함에 따라(여기에서 새로운 스타트업을 구축한다고 상상해 보세요) 두 개 이상의 클래스에 동일한 작업을 수행하는 여러 메서드가 있는 때가 올 수 있습니다. 이런 일이 발생하면 상황을 건조하게 유지하고 반복하지 않도록 해야 함을 의미합니다. 문제는 이러한 클래스 간에 기능을 공유하는 방법과 관련이 있습니다.

이전에 모듈을 사용한 적이 없다면 이러한 "공유" 메서드에 대해 엄격하게 새 클래스를 만들고 싶은 유혹을 받을 수 있습니다. 그러나 그렇게 하면 특히 Ruby가 지원하지 않는 다중 상속을 사용해야 하는 경우 부정적인 결과를 초래할 수 있습니다. 모듈은 이 경우를 처리하는 가장 좋은 수단입니다. 모듈은 클래스와 유사하지만 몇 가지 차이점이 있습니다. 먼저, 다음은 모듈이 어떻게 생겼는지에 대한 예입니다:

module Movement
  def walk
    puts "I can walk!"
  end
end
  1. 정의는 module로 시작합니다. class 대신 키워드 .
  2. 모듈은 인스턴스를 가질 수 없으므로 Movement.new를 사용할 수 없습니다. .

방법

메서드는 특정 개체가 수행하는 작업으로 볼 수 있습니다. [2, 3, 4]와 같은 배열이 있는 경우 numberList라는 변수에 할당됨 , .push 메소드는 put하기 위해 배열에서 수행할 수 있는 작업입니다. 배열로 받는 값입니다. 이 코드 스니펫은 예시입니다.

john.walk

john Human의 인스턴스인 개체를 참조합니다. , 및 walk 방법이다. 그러나 추론된 메서드는 개체의 클래스, 슈퍼클래스 또는 혼합에서 오는 경향이 있기 때문에 이것은 완전히 사실이 아닙니다. 모듈.

john과 같은 객체라도 객체에 메서드를 정의할 수 있다는 점을 추가하는 것이 중요합니다. , Ruby에서는 객체 생성에 사용되는 클래스도 모두 객체이기 때문입니다.

def john.drip
  puts "My drip is eternal"
end

drip 메소드는 john에 할당된 개체에서만 액세스할 수 있습니다. . drip john이(가) 사용할 수 있는 싱글톤 메서드입니다. 물체. 이 스택 오버플로 답변에서 볼 수 있듯이 싱글톤 메서드와 클래스 메서드 간에 차이가 없다는 것을 아는 것이 중요합니다. 위의 예와 같이 객체에 정의된 메서드를 언급하지 않는 한 메서드가 특정 객체에 속한다고 말하는 것은 옳지 않습니다. 이 예에서 walk 메소드는 Movement에 속합니다. 모듈, 동안 hello 메소드는 Human에 속합니다. 수업. 이러한 이해를 바탕으로 한 단계 더 나아가 객체에서 호출되는 정확한 메서드를 결정하기 위해 Ruby는 객체의 클래스 또는 상위 클래스 또는 혼합된 모듈을 확인해야 합니다. 개체의 계층 구조에서.

믹싱 모듈

Ruby는 단일 상속만 지원합니다. 클래스는 하나의 클래스에서만 상속할 수 있습니다. 이렇게 하면 자식 클래스가 다른 클래스의 동작(메서드)을 상속할 수 있습니다. 다른 클래스에서 공유해야 하는 동작이 있으면 어떻게 됩니까? 예를 들어, walk를 만들려면 Human 인스턴스에 사용할 수 있는 메서드 혼합할 수 있습니다. Movement Human의 모듈 수업. 따라서 Human include를 사용하는 클래스 다음과 같이 표시됩니다.

require "movement" # Assuming we have the module in a file called movement.rb

class Human
  include Movement

  attr_reader :name

  def initialize(name)
    @name = name
  end

  def hello
    put "Hello! #{name}"
  end
end

이제 walk를 호출할 수 있습니다. 인스턴스의 메소드:

john = Human.new("John")
john.walk

포함

포함을 사용할 때 키워드는 위에서 했던 것처럼 포함된 모듈의 메서드가 인스턴스 메서드로 클래스에 추가됩니다. 포함하기 때문입니다. 모듈이 상위 사이에 추가됨 HumanMovement 모듈은 Human의 부모로 볼 수 있습니다. 수업. 위에 표시된 예에서 볼 수 있듯이 walk Human 인스턴스의 메서드 수업.

연장

포함 외에 , Ruby는 확장을 제공합니다. 예어. 이것은 모듈의 메소드를 클래스 메소드로 클래스에서 사용할 수 있게 합니다. 이는 이전에 배운 것처럼 싱글톤 메소드라고도 합니다. 따라서 Feeding이라는 모듈이 있는 경우 처럼 보입니다

module Feeding
  def food
    "I make my food :)"
  end
end

그런 다음 Human에서 이 동작을 공유할 수 있습니다. 이를 요구하고 extend Feeding을 추가하여 클래스 . 그러나 사용하려면 food를 호출하는 대신 클래스 인스턴스에서 메서드를 호출하는 경우 클래스 메서드를 호출하는 것과 같은 방식으로 클래스 자체에서 호출합니다.

Human.food

앞에

이는 포함과 유사합니다. 그러나 이 게시물에 명시된 바와 같이 약간의 차이점이 있습니다.

<블록 인용>

클래스와 체인의 상위 클래스 사이에 모듈을 삽입하는 대신 클래스 자체보다 먼저 체인 맨 아래에 모듈을 삽입한다는 점을 제외하면 실제로는 포함처럼 작동합니다.

이것이 의미하는 바는 클래스 인스턴스에서 메소드를 호출할 때 Ruby는 클래스를 조사하기 전에 모듈 메소드를 조사한다는 것입니다.

hello를 정의하는 모듈이 있는 경우 그런 다음 Human prepend를 사용하여 클래스 , Ruby는 클래스에 있는 메소드 대신 모듈에 있는 메소드를 호출합니다.

Ruby의 prepend 방식을 올바르게 이해하려면 이 기사를 살펴보는 것이 좋습니다.

메서드 조회 경로

Ruby 인터프리터가 메소드를 호출하려고 할 때 가장 먼저 찾는 곳은 싱글톤 메소드입니다. 가능한 결과를 보기 위해 재생할 수 있는 이 repl을 만들었습니다.

다음과 같은 많은 모듈과 클래스가 있다고 가정합니다.

module One
  def another
    puts "From one module"
  end
end

module Two
  def another
    puts "From two module"
  end
end

module Three
  def another
    puts "From three module"
  end
end

class Creature
  def another
    puts "From creature class"
  end
end

이것들을 Human에 섞어봅시다. 수업.

class Human < Creature
  prepend Three
  extend Two
  include One

  def another
    puts "Instance method"
  end

  def self.another
    puts "From Human class singleton"
  end
end

모듈을 혼합하는 것 외에도 인스턴스와 클래스 메서드가 있습니다. 또한 Human class는 Creature의 하위 클래스입니다. 수업.

첫 번째 조회 - 싱글톤 방법

Human.another를 실행할 때 , 인쇄되는 것은 From Human class singleton입니다. , 이것은 우리가 클래스 메소드에 가지고 있는 것입니다. 클래스 메서드를 주석 처리하고 다시 실행하면 From two module이 인쇄됩니다. 콘솔에. 이것은 extend를 사용하여 혼합한 모듈에서 가져온 것입니다. . 싱글톤 메소드 사이에서 조회가 시작됨을 보여줍니다. extend Two를 제거(또는 주석 처리)하면 명령을 다시 실행하면 메서드 누락 오류가 발생합니다. . Ruby가 another을(를) 찾을 수 없기 때문에 이 오류가 발생합니다. 싱글톤 방식 중 방식입니다.

인스턴스를 만들어 클래스 인스턴스를 사용하겠습니다.

n = Human.new

또한 인스턴스에 대한 싱글톤 메서드를 생성합니다.

def n.another
  puts "From n object"
end

이제 n.another를 실행하면 , 호출되는 버전은 n에 정의된 싱글톤 메서드입니다. 물체. Ruby가 extend를 사용하여 혼합된 모듈을 호출하지 않는 이유 이 경우 클래스의 인스턴스에서 메서드를 호출하기 때문입니다. 싱글톤 메소드는 extend를 사용하여 혼합된 모듈을 포함하는 메소드보다 관련성이 더 높다는 것을 아는 것이 중요합니다. .

두 번째 조회 - preprend를 사용하여 혼합된 모듈

n에서 싱글톤 메서드를 주석 처리하면 개체를 만들고 명령을 실행하면 호출되는 메서드의 버전이 prepend를 사용하여 혼합한 모듈입니다. . prepend를 사용하기 때문입니다. 클래스 자체 앞에 모듈을 삽입합니다.

세 번째 조회 - 수업

Three 모듈을 주석 처리하면 , another 버전 호출되는 메소드는 클래스에 정의된 인스턴스 메소드입니다.

네 번째 조회 - include를 사용하여 혼합된 모듈

Ruby가 메소드를 검색하는 다음 위치는 include를 사용하여 혼합된 모듈에 있습니다. . 따라서 인스턴스 메서드를 주석 처리하면 One 모듈에 있는 버전이 표시됩니다. .

다섯 번째 조회 - 상위 클래스

클래스에 부모 클래스가 있는 경우 Ruby는 해당 클래스에서 검색합니다. 검색에는 상위 클래스에 혼합된 모듈로 이동하는 것이 포함됩니다. Creature에 혼합된 모듈에 정의된 메서드가 있는 경우 클래스에서 메서드가 호출됩니다.

메소드의 검색이 끝나는 위치를 조상을 확인하여 알 수 있습니다. .ancestors 호출 수업에. Human을 위해 이 작업을 수행합니다. 클래스는 [Three, Human, One, Creature, Object, Kernel, BasicObject]를 반환합니다. . 메소드 검색은 BasicObject에서 끝납니다. 클래스는 Ruby의 루트 클래스입니다. BasicObject에서 시작된 일부 클래스의 인스턴스인 모든 개체 수업.

메소드 검색이 개발자가 정의한 상위 클래스를 지나면 다음과 같이 됩니다.

  • Object 수업
  • Kernel 모듈
  • BasicObject 수업

method_missing 방법

Ruby를 한동안 사용해 왔다면 아마도 NoMethodError를 보았을 것입니다. , 개체에 대해 알 수 없는 메서드를 시도할 때 발생합니다. 이것은 Ruby가 객체의 조상을 거쳐 호출된 메서드를 찾지 못한 후에 발생합니다. 수신한 오류 메시지는 method_missing에 의해 처리됩니다. BasicObject에 정의된 메소드 수업. 메서드를 호출하는 개체에 대한 메서드를 재정의할 수 있으며 이를 확인하여 알아볼 수 있습니다.

결론

이제 Ruby가 객체에서 호출된 메서드를 파악하는 데 사용하는 경로를 알았습니다. 이를 이해하면 개체에 대해 알 수 없는 메서드를 호출한 결과 발생하는 오류를 쉽게 수정할 수 있습니다.