아니요, 불행히도 한 객체가 다른 객체를 완전히 시뮬레이트 할 수 없습니다. 다른 것을 시뮬레이트하는 하나의 객체가 객체 지향의 토대 중 하나이고 Ruby가 객체 지향 언어이므로이 작업이 실제로 가능해야하기 때문에 이것은 불행한 제한입니다.
불가능 이유를 세 가지 이유가 있습니다 :
- 참조 평등 : 참조 평등 (
BasicObject#equal?
가) OO하여 시뮬레이션을 중단하고,이. Reference Equality를 비교하면 시뮬레이션 대상과 시뮬레이션 대상을 구별 할 수 있지만 가능하지 않아야합니다. 원숭이 패치 BasicObject
을 사용하여 equal?
을 제거하거나 바꿀 수는 있지만 그럴 경우 왼쪽 및 오른쪽 문제가 발생할 수 있습니다.
- 부울 연산자와 조건문은 : 부울 연산자와 조건문은 두 개의 싱글 객체
nil
및 false
이 falsy이라고 생각. falsy 개체를 작성할 방법이 없기 때문에 nil
또는 false
을 시뮬레이트 할 방법이 없습니다.
- 프로토콜 대신 클래스 : 일부 핵심 라이브러리 및 표준 라이브러리 메소드 및 일부 하드 코딩 된 내부 클래스는 객체가 특정 클래스의 인스턴스가 될 것을 기대합니다. 동일한 프로토콜을 사용하는 객체는 해당 클래스와 관계없이 동일한 유형이어야합니다.
당신은하지만, 아주 멀리 얻을 수 있습니다 :
- 거의 방법을 (실제로, 어떤 방법, 나는 믿지) 참조 평등의 핵심 라이브러리와 표준 라이브러리 검사에서.
nil
또는 false
을 시뮬레이션 할 필요가 거의 없습니다.
- 특정 서브 루틴이 특정 클래스를 필요로 할 때 거의 항상 간접 해치를 이스케이프 해치로 제공하고 일부 변환 방법을 호출합니다 (예 :단항 프리픽스 앰퍼샌드
&
연산자 *
"스 플랫"연산자는 단항 to_a
호출 프리픽스 별표 print
통화 to_s
, Array#[]
to_int
통화 등), to_proc
부른다. 또한 최소한 Numeric
초 동안 정의 된 강제 프로토콜이 있습니다.
그러나, 특정 경우에, 당신은 단순히 작동하지 않습니다 이러한 경우 중 하나에 실행 to_ary
당신이 당신의 경우에, Array
을 시뮬레이션 무언가를 만드는 향해 먼 길을 얻을 수있는 동안, 당신은 필요 을 계속 추적하지만 물론 Array
으로 변환하면 ID와 추가 동작이 모두 손실됩니다. 불행히도, 당신은 망했다. 더 이상 할 수있는 일이 없습니다.
동일한 프로토콜을 사용하는 두 객체는 동일한 유형으로 간주되어야하며 Array#concat
은 인수가 Array
의 인스턴스인지 여부를 신경 쓰지 않아야합니다 (또는로 변환 될 수 있음). 하나의)하지만 그 인수가 Array
과 같은 프로토콜을 말하는지 (정확하게 말하자면 : concat
실제로이 필요로하는 프로토콜의 부분 집합을 말합니다).
왜 이런 경우에 루비가 OO 패러다임을 따르지 않는지 추측 할 수 있습니다. 성능. OO에서 두 객체가 같은 유형 (또는 같은 클래스)이라도 한 객체는 다른 객체의 표현을 결코 알 수 없습니다. 이 사이의 근본적인 차이이다 객체 지향 추상 데이터 유형에 따라 데이터 추상화와 데이터 추상화 : ADT 인스턴스는 동일한 유형의 다른 인스턴스의 표현을 검사 할 수 있습니다 개체 수 어떤 다른 개체의하지 표현, 동일한 유형 (또는 클래스) 인 경우에도 마찬가지입니다.
그러나 이는 두 작업을 한꺼번에 검사 할 수 없다는 것을 의미합니다. 작업은 세 번째 개체의 메서드로, 두 개체의 표현을 검사 할 수 없거나 두 객체 중 하나의 메소드인데,이 경우 자신의 객체의 표현을 검사 할 수 있지만 다른 객체의 표현은 검사 할 수 없음), 이는 OO에서 두 객체의 표현에 대한 액세스가 필요한 작업을 한 번에 작성할 수 없음을 의미합니다.
예. 첫 번째 목록의 마지막 요소의 next
포인터에 액세스 할 수 있고 두 번째 목록의 첫 번째 요소의 prev
포인터에 액세스 할 수 있지만 OO에서는 두 목록 중 하나만 액세스 할 수있는 경우 두 개의 연결된 목록을 연결하는 것은 O (1)입니다. 명시 적으로 두 포인터에 대한 액세스를 제공하는 공용 메서드를 노출합니다. 그리고 배열을 다른 배열에 연결하려면 두 배열의 내부 표현에 대한 액세스가 빠르기 때문에 Ruby는 여기에서 OO 캡슐화를 중단하기로 결정하고 두 객체 모두 내부 메모리 레이아웃을 알고있는 클래스 여야합니다.
이것은 유감 스럽지만 완전히 OO는 아니지만 Smalltalk와 같은 "하드 코어 OO"언어조차도 핵심 데이터 유형 중 일부를 만들 수 있다는 단점이 있습니다. (예 : 숫자, 문자열, 배열 및 부울)
핵심 라이브러리의 상당 부분이 구현 내부에 대한 권한있는 액세스로 구현되는 YARV, JRuby 및 기타 구현과 같은 경우에는 다음과 같은 또 다른 문제가 있습니다. 보다 편리한 구현을 위해 루비 의미를 우회하는 핵심 방법에 대해 매우 유혹적이다.전혀 상관없는 예 : Enumerable#inject
의 다양한 복잡한 "오버로드"를 C의 YARV 또는 Java의 JRuby에서 구현하는 것은 쉽습니다. YARV에서 C 함수는 인터프리터 내부에 대한 권한있는 액세스 권한을 가지며 전달 된 인수를 검사 할 수 있습니다 누군가가 Ruby에서 메소드를 다시 구현하려고 시도하는 방법은 JRuby에서 실제 자바 오버로드 된 메소드처럼 오버로드 된 메소드를 구현할 수있는 접착제 마법이 없다.
마찬가지로 모든 핵심 메소드는 구현의 GC 메모리에있는 객체의 내부 표현에 대한 권한있는 액세스를 가지므로 class
, is_a?
을 거치지 않고 객체의 클래스를 직접 검사하여 객체의 클래스를 검사합니다. kind_of?
또는 instance_of?
그냥'Array'에서'IArray'를 상속받을 수 있습니까? –
_ 이상의 변환이 필요하지 않습니다. ""구현 한 is_a?와'kind_of?'는'a2' "_에 해당합니다. 게다가, 당신의 코드는 나를 위해 잘 작동합니다. 'concat'은'method_missing'에 의해 처리/전달되는'to_ary'를 호출합니다. – Stefan
Stefan 저는 IArray 클래스에서 _is_a? _ 및 kind_of? _를 구현했으며 절대 호출되지 않습니다. concat이 to_ary를 호출하지만 to_ary의 반환 값은 배열이어야하며 제 경우에는 @array를 반환 할 수 없습니다. 호출이 method_missing을 통과하게하고 싶습니다. –