3.2.1 제약(Constraints)
3.2.1 제약(Constraints)
타입 매개변수는 여러 타입으로 제약될 수 있어요:
typedef Measurable = {
public var length(default, null):Int;
}
class Main {
static public function main() {
trace(test([]));
trace(test(["bar", "foo"]));
// String should be Iterable
// test("foo");
}
#if (haxe_ver >= 4)
static function test<T:Iterable<String> & Measurable>(a:T) {
#else
static function test<T:(Iterable<String>, Measurable)>(a:T) {
#end
if (a.length == 0)
return "empty";
return a.iterator().next();
}
}
test 메서드는 Iterable<String>과 Measurable 두 타입으로 제약된 타입 매개변수 T를 가져요. 후자는 편의를 위해 typedef로 정의되며, 호환 타입이 Int 타입의 읽기 전용 속성(property) length를 가지도록 요구합니다. 그러면 제약 조건은 어떤 타입이 다음과 같을 때 호환된다는 것을 나타냅니다.
Iterable<String>과 호환되고Int타입의length속성을 가진다.
위 예제에서 7행의 빈 배열과 8행의 Array<String>으로 test를 호출하는 것이 잘 동작하는 것을 볼 수 있어요. Array가 length 속성과 iterator 메서드를 모두 가지기 때문이에요. 하지만 9행처럼 String을 인자로 전달하면 제약 검사를 통과하지 못합니다. String이 Iterable<T>와 호환되지 않기 때문이에요.
단일 타입으로 제약할 때는 괄호를 생략할 수 있어요:
class Main {
static public function main() {
trace(test([]));
trace(test(["bar", "foo"]));
}
static function test<T:Iterable<String>>(a:T) {
return a.iterator().next();
}
}
Haxe 4.0.0 이후 — 매크로에서 이 문법의 동작 방식이 약간 달라요. 매크로 컨텍스트에서는
T:Iterable<String> & Measurable형태가 구조적 제약(structural constraints)과 다르게 취급될 수 있으니 주의해야 합니다. (상세는 원문 참고)
출처: Constraints
본문
제약의 표현
타입 매개변수 제약은 T:제약타입 형태로 : 뒤에 타입을 나열해요. 여러 타입으로 제약할 때는 &(Haxe 4)나 쉼표/괄호(Haxe 4 이전)로 연결합니다.
제약의 의미
제약은 호환 타입이 반드시 만족해야 하는 요건을 정의해요. 예를 들어 Iterable<String> & Measurable 제약은 Iterable<String>과 호환되면서 Int 타입의 length 속성을 가질 것을 요구합니다. String은 Iterable이 아니므로 이 제약을 통과하지 못해요.
단일 제약
제약이 하나면 괄호를 생략할 수 있어요. T:Iterable<String>처럼 씁니다.