예외
예외는 특별한 유형의 variant입니다, 예외적인 경우에 "던져집니다" (남용하지 마세요!).
사용
let getItem = (theList) =>
if (callSomeFunctionThatThrows()) {
/* 찾은 아이템을 반환 */
} else {
raise(Not_found)
};
let result =
try (getItem([1, 2, 3])) {
| Not_found => 0 /* getItem이 에러를 던질 시의 기본 값 */
};
Note that the above is just for demonstration purposes; in reality, you'd return an option(int) directly from getItem and avoid the try altogether.
You can directly match on exceptions while getting another return value from a function:
switch (List.find((i) => i === theItem, myItems)) {
| item => print_endline(item)
| exception Not_found => print_endline("아이템을 찾을 수 없습니다!")
};
You can also make your own exceptions like you'd make a variant (exceptions need to be capitalized too).
exception InputClosed(string);
...
raise(InputClosed("스트림이 닫혀있습니다!"));
팁 & 트릭
보통의 경우, 예외는 필요 없을 겁니다. 예를 들어, 콜렉션에서 item을 찾을 수 없을 때 예외를 던지는 대신, option(item)을 반환(찾을 수 없는 경우에는 None을 반환)하는 거죠.
디자인 결정
The above tip seems to contradict what's happening in the OCaml standard library; prominent functions in modules such as List and String seems to throw exceptions overly often. This is partially a historical sediment, and partially out of extreme care for performance. Native OCaml/Reason is incredibly performant; exception throwing was designed to be very cheap, cheaper than allocating and returning e.g. an option. This is unfortunately not the case for JavaScript.
Newer standard library alternatives usually come with option-returning functions rather than exception-throwing ones. For example, List.find has the option-returning counterpart List.find_opt, which doesn't throw.
Exceptions are actually just variants too. In fact, they all belong to a single variant type, called exn. It's an extensible variant, meaning you can add new constructors to it, such as InputClosed above. exception Foo is just a sugar for adding a constructor to exn.