개인 클래스 메소드를 작성하는 이러한 접근 방식은 어떻게 작동합니까?
class Person
def self.get_name
persons_name
end
class << self
private
def persons_name
"Sam"
end
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"
그러나 이것은하지 않습니다 :
class Person
def self.get_name
persons_name
end
private
def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
답변
private
명시 적 객체 (귀하의 경우 self
) 에서 메소드를 정의하는 경우 작동하지 않는 것 같습니다 . private_class_method
클래스 메소드를 개인용 (또는 설명 된대로)으로 정의 하는 데 사용할 수 있습니다 .
class Person
def self.get_name
persons_name
end
def self.persons_name
"Sam"
end
private_class_method :persons_name
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
또는 (ruby 2.1+에서), 메소드 정의는 메소드 이름의 심볼을 반환하기 때문에 다음과 같이 사용할 수도 있습니다 :
class Person
def self.get_name
persons_name
end
private_class_method def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
답변
루비의 그런 행동은 정말 실망입니다. 개인 섹션 self.method로 이동하면 개인 섹션이 아닙니다. 그러나 클래스 << self로 옮기면 갑자기 작동합니다. 역겨워 요.
아마도 혼란 스러울 수도 있고, 좌절 할 수도 있지만, 역겨운 것은 아닙니다.
루비의 객체 모델을 이해하고 대응하면 그것은 완벽한 의미가 있습니다 방법은 흐름 조회 , 특히 그 고려 때 private
입니다 NOT 액세스 / 가시성 수정, 실제로 메소드 호출 (의 수신자로 클래스와) 논의 여기 … 루비에는 “비공개 섹션” 과 같은 것이 없습니다 .
프라이빗 인스턴스 메소드 를 정의하려면 private
인스턴스의 클래스를 호출 하여 이후에 정의 된 메소드의 기본 가시성을 프라이빗으로 설정합니다. 따라서 클래스의 클래스를 호출 하여 프라이빗 클래스 메소드 를 정의하는 것이 좋습니다 private
. 메타 클래스.
자체적으로 선포 된 다른 OO 언어는 혼동을 줄 이겠지만, Ruby의 메타 프로그래밍 기능을 사용하지 않으면 서 혼동스럽고 일관성이 없는 (일관되지 않은 ) 오브젝트 모델 과 비교할 수 있습니다.
답변
기본적으로 모든 클래스 메소드는 공용입니다. 그것들을 비공개로 만들려면 @tjwallace가 작성한 것처럼 모듈 #private_class_method를 사용하거나 다르게 정의 할 수 있습니다.
class << self
private
def method_name
...
end
end
class << self
self의 singleton 클래스를 열어 현재 self 객체에 대해 메소드를 재정의 할 수 있습니다. 클래스 / 모듈 ( “정적”) 메소드를 정의하는 데 사용됩니다. 개인 메소드를 정의하면 실제로 개인 클래스 메소드가 제공됩니다.
답변
완전성을 위해 private_class_method를 별도의 행으로 선언하는 것을 피할 수도 있습니다. 나는 개인적 으로이 사용법을 좋아하지 않지만 그것이 존재한다는 것을 아는 것이 좋습니다.
private_class_method def self.method_name
....
end
답변
나도이 영역에서 루비 (또는 최소한 그것에 대한 지식)가 부족하다는 것을 알게된다. 예를 들어 다음은 내가 원하는 것을 수행하지만 서투른 것입니다.
class Frob
attr_reader :val1, :val2
Tolerance = 2 * Float::EPSILON
def initialize(val1, val2)
@val2 = val1
@val2 = val2
...
end
# Stuff that's likely to change and I don't want part
# of a public API. Furthermore, the method is operating
# solely upon 'reference' and 'under_test' and will be flagged as having
# low cohesion by quality metrics unless made a class method.
def self.compare(reference, under_test)
# special floating point comparison
(reference - under_test).abs <= Tolerance
end
private_class_method :compare
def ==(arg)
self.class.send(:compare, val1, arg.val1) &&
self.class.send(:compare, val2, arg.val2) &&
...
end
end
위의 코드에서 내 문제는 Ruby 구문 요구 사항과 코드 품질 메트릭이 번거로운 코드를 만들기 위해 노력한다는 것입니다. 코드를 원하는대로 작동시키고 메트릭을 조용하게하려면 compare ()를 클래스 메서드로 만들어야합니다. 클래스의 공개 API에 포함시키고 싶지 않기 때문에 비공개이어야하지만 ‘비공개’자체로는 작동하지 않습니다. 대신 ‘private_class_method’또는 이와 같은 해결 방법을 사용해야합니다. 이것은 차례로 ‘== ()’에서 테스트하는 각 변수에 대해 ‘self.class.send (: compare …’를 사용하도록 강요합니다.
답변
인스턴스 메소드는 클래스 정의 블록 내에 정의됩니다. 클래스 메소드는 클래스의 싱글 톤 클래스에서 “메타 클래스”또는 “고유 클래스”라고도하는 싱글 톤 메소드로 정의됩니다. private
키워드가 아니라 메소드 ( Module # private )입니다.
이 메소드의 호출이다 self#private
/ A#private
그렇지 않으면 전환 될 때까지 모든 향후 인스턴스 메소드 정의에 대한에 개인 액세스를 “전환”
class A
private
def instance_method_1; end
def instance_method_2; end
# .. and so forth
end
앞에서 언급했듯이 클래스 메소드는 실제로 싱글 톤 클래스에 정의 된 싱글 톤 메소드입니다.
def A.class_method; end
또는 특수 구문을 사용하여 익명의 싱글 톤 클래스 A의 정의 본문을 엽니 다.
class << A
def class_method; end
end
“메시지 개인” -self -inside 의 수신자는 class A
클래스 오브젝트 A입니다. class << A
블록 안의 self 는 또 다른 오브젝트 인 singleton 클래스입니다.
다음 예제는 실제로 호출에 대해 두 개의 다른 수신자 또는 대상을 사용하여 private 이라는 두 개의 다른 메소드를 호출하는 것입니다. 첫 번째 부분에서는 프라이빗 인스턴스 메소드 ( “클래스 A”)를 정의하고, 후자에서는 프라이빗 클래스 메소드 (실제로 A의 싱글 톤 클래스 오브젝트에 대한 싱글 톤 메소드)를 정의합니다.
class A
# self is A and private call "A.private()"
private def instance_method; end
class << self
# self is A's singleton class and private call "A.singleton_class.private()"
private def class_method; end
end
end
이제이 예제를 약간 다시 작성하십시오.
class A
private
def self.class_method; end
end
[루비 언어 디자이너]가 저지른 실수를 볼 수 있습니까? 다가오는 A의 모든 인스턴스 메소드에 대한 개인 액세스를 토글하지만 다른 클래스 인 싱글 톤 클래스에서 싱글 톤 메소드를 계속 선언하십시오.
답변
루비는 나쁜 해결책을 제시하는 것 같습니다. 설명하려면 개인 클래스 메소드에 대한 액세스를 보여주는 간단한 C ++ 예제로 시작하십시오.
#include <iostream>
class C
{
public:
void instance_method(void)
{
std::cout << "instance method\n";
class_method(); // !!! LOOK !!! no 'send' required. We can access it
// because 'private' allows access within the class
}
private:
void static class_method(void) { std::cout << "class method\n"; }
};
int main()
{
C c;
c.instance_method(); // works
// C::class_method() does not compile - it's properly private
return 0;
}
위의 실행
% ./a.out
instance method
class method
이제 루비는 동등한 것을 제공하지 않는 것 같습니다. 루비의 규칙은 개인 메소드에 수신자가 접근해서는 안된다는 것입니다. 그건,
inst.pvt_method # FAILS
pvt_method # WORKS only within the class (good)
개인 인스턴스 메서드에는 문제가 없지만 개인 클래스 메서드에 문제가 발생합니다.
루비가 이런 식으로 작동하기를 원합니다.
class C
def instance_method
STDOUT << "instance method\n"
# Simple access to the private class method would be nice:
class_method # DOES NOT WORK. RUBY WON'T FIND THE METHOD
C.class_method # DOES NOT WORK. RUBY WON'T ALLOW IT
# ONLY THIS WORKS. While I am happy such capability exists I think
# the way 'send' should be used is when the coder knows he/she is
# doing a no-no. The semantic load on the coder for this is also
# remarkably clumsy for an elegant language like ruby.
self.class.send(:class_method)
end
private_class_method def self.class_method() STDOUT << "class method\n"; end
end
그러나 아아, 위의 방법은 효과가 없습니다. 누군가 더 나은 방법을 알고 있습니까?
메소드 전에 ‘보내기’를 볼 때 코드가 API 디자이너의 의도를 위반하고 있다는 명백한 징후이지만,이 경우 디자인은 클래스의 인스턴스 메소드가 전용 클래스 메소드를 호출하도록하는 것입니다.