Ruby에서 coerce ()는 실제로 어떻게 작동합니까?
수업이 Point
있고 point * 3
다음과 같이 수행하는 방법을 안다고합니다 .
class Point
def initialize(x,y)
@x, @y = x, y
end
def *(c)
Point.new(@x * c, @y * c)
end
end
point = Point.new(1,2)
p point
p point * 3
산출:
#<Point:0x336094 @x=1, @y=2>
#<Point:0x335fa4 @x=3, @y=6>
하지만,
3 * point
이해되지 않음 :
Point
Fixnum
(TypeError
) (으 ) 로 강요 할 수 없습니다.
따라서 인스턴스 메서드를 추가로 정의해야합니다 coerce
.
class Point
def coerce(something)
[self, something]
end
end
p 3 * point
산출:
#<Point:0x3c45a88 @x=3, @y=6>
이 상기되고 그래서 3 * point
동일하다 3.*(point)
. 즉, 인스턴스 메소드 *
는 인수를 취하고 point
객체를 호출합니다 3
.
자,이 방법 *
은 점을 곱하는 방법을 모르기 때문에
point.coerce(3)
호출되고 배열을 다시 가져옵니다.
[point, 3]
다음 *
번에 다시 적용됩니다, 그게 사실입니까?
이제 이것은 이해되었고 이제 우리 는 클래스 Point
의 인스턴스 메소드 *
에 의해 수행되는 새로운 객체를 갖게 되었습니다 Point
.
질문은 ~이야:
누가 호출
point.coerce(3)
합니까? Ruby가 자동으로 실행 되나요, 아니면 예외를 잡아서*
메소드 내부에 코드가Fixnum
있나요? 또는case
알려진 유형 중 하나를 모르는 경우 다음을 호출한다는 진술에 의한 것coerce
입니까?coerce
항상 2 개 요소의 배열을 반환해야 합니까 ? 배열이 아닐 수 있습니까? 아니면 3 개 요소의 배열 일 수 있습니까?그리고 원래 연산자 (또는 메서드)
*
가 요소 1의 인수와 함께 요소 0에서 호출 된다는 규칙 입니까? (요소 0과 요소 1은에서 반환 한 배열의 두 요소입니다coerce
.) 누가 수행합니까? Ruby에 의해 수행Fixnum
됩니까 , 아니면 코드에 의해 수행 됩니까? 에서 코드에 의해 수행되는 경우Fixnum
강제를 수행 할 때 모두가 따르는 "관습"입니까?그래서의 코드 수
*
의Fixnum
이 같은 일을 :class Fixnum def *(something) if (something.is_a? ...) else if ... # other type / class else if ... # other type / class else # it is not a type / class I know array = something.coerce(self) return array[0].*(array[1]) # or just return array[0] * array[1] end end end
그래서
Fixnum
의 인스턴스 메서드에 뭔가를 추가하는 것이 정말 어렵coerce
습니까? 그것은 이미 많은 코드를 가지고 있으며 우리는 그것을 향상시키기 위해 몇 줄을 추가 할 수는 없습니다 (하지만 우리가 원할까요?).coerce
의Point
클래스는 매우 일반적이며 작동*
또는+
그들이 전이 때문이다. Point minus Fixnum을 다음과 같이 정의하는 경우와 같이 전 이적이지 않은 경우에는 어떻게됩니까?point = Point.new(100,100) point - 20 #=> (80,80) 20 - point #=> (-80,-80)
짧은 대답 : 어떻게 Matrix
하고 있는지 확인 하십시오 .
The idea is that coerce
returns [equivalent_something, equivalent_self]
, where equivalent_something
is an object basically equivalent to something
but that knows how to do operations on your Point
class. In the Matrix
lib, we construct a Matrix::Scalar
from any Numeric
object, and that class knows how to perform operations on Matrix
and Vector
.
To address your points:
Yes, it is Ruby directly (check calls to
rb_num_coerce_bin
in the source), although your own types should do too if you want your code to be extensible by others. For example if yourPoint#*
is passed an argument it doesn't recognize, you would ask that argument tocoerce
itself to aPoint
by callingarg.coerce(self)
.Yes, it has to be an Array of 2 elements, such that
b_equiv, a_equiv = a.coerce(b)
Yes. Ruby does it for builtin types, and you should too on your own custom types if you want to be extensible:
def *(arg) if (arg is not recognized) self_equiv, arg_equiv = arg.coerce(self) self_equiv * arg_equiv end end
The idea is that you shouldn't modify
Fixnum#*
. If it doesn't know what to do, for example because the argument is aPoint
, then it will ask you by callingPoint#coerce
.Transitivity (or actually commutativity) is not necessary, because the operator is always called in the right order. It's only the call to
coerce
which temporarily reverts the received and the argument. There is no builtin mechanism that insures commutativity of operators like+
,==
, etc...
If someone can come up with a terse, precise and clear description to improve the official documentation, leave a comment!
I find myself often writing code along this pattern when dealing with commutativity:
class Foo
def initiate(some_state)
#...
end
def /(n)
# code that handles Foo/n
end
def *(n)
# code that handles Foo * n
end
def coerce(n)
[ReverseFoo.new(some_state),n]
end
end
class ReverseFoo < Foo
def /(n)
# code that handles n/Foo
end
# * commutes, and can be inherited from Foo
end
참고URL : https://stackoverflow.com/questions/2799571/in-ruby-how-does-coerce-actually-work
'Development Tip' 카테고리의 다른 글
호스팅 된 TeamCity 빌드 공급자를 아는 사람이 있습니까? (0) | 2020.12.05 |
---|---|
iOS Swift에서 원격 JSON 데이터를 로컬 캐시 저장소에 동기화 (0) | 2020.12.05 |
WChars, 인코딩, 표준 및 이식성 (0) | 2020.12.05 |
문서화 된 JavaScript 함수에 대한 Github 친화적 마크 다운을 쉽게 만드는 방법은 무엇입니까? (0) | 2020.12.05 |
신속한 숫자 및 CGFloat (CGPoint, CGRect 등) (0) | 2020.12.05 |