@call
@call
함수를 호출하는 빌트인인데, 소괄호로 감싼 호출과 같은 일을 하면서도 호출 방식을 더 세밀하게 제어할 수 있어요. 어디에 쓸 수 있는지 보여드릴게요.
본문
@call 은 modifier 를 받아서 함수를 호출해요. 시그니처는 이렇게 생겼어요.
@call(modifier: std.lang.CallModifier, function: anytype, args: anytype) anytype
함수를 호출한다는 점은 표현식을 소괄호로 감싸서 호출하는 방식과 같아요.
const expectEqual = @import("std").testing.expectEqual;
test "noinline function call" {
try expectEqual(12, @call(.auto, add, .{ 3, 9 }));
}
fn add(a: i32, b: i32) i32 {
return a + b;
}
실행 결과는 이렇게 나와요.
$ zig test test_call_builtin.zig
1/1 test_call_builtin.test.noinline function call...OK
All 1 tests passed.
일반 함수 호출 문법보다 @call 이 유연한 이유는, 호출 방식을 결정하는 CallModifier 열거형을 첫 인자로 넘길 수 있기 때문이에요. 그 열거형을 그대로 옮기면 아래와 같아요.
pub const CallModifier = enum {
/// Equivalent to function call syntax.
auto,
/// Prevents tail call optimization. This guarantees that the return
/// address will point to the callsite, as opposed to the callsite's
/// callsite. If the call is otherwise required to be tail-called
/// or inlined, a compile error is emitted instead.
never_tail,
/// Guarantees that the call will not be inlined. If the call is
/// otherwise required to be inlined, a compile error is emitted instead.
never_inline,
/// Asserts that the function call will not suspend. This allows a
/// non-async function to call an async function.
no_suspend,
/// Guarantees that the call will be generated with tail call optimization.
/// If this is not possible, a compile error is emitted instead.
always_tail,
/// Guarantees that the call will be inlined at the callsite.
/// If this is not possible, a compile error is emitted instead.
always_inline,
/// Evaluates the call at compile-time. If the call cannot be completed at
/// compile-time, a compile error is emitted instead.
compile_time,
};
각 modifier가 하는 일을 간단히 짚어볼게요.
auto— 일반 함수 호출 문법과 동일해요.never_tail— 꼬리 호출 최적화를 막아요. 반환 주소가 호출 지점(callsite)을 가리키는 걸 보장하죠. 만약 꼬리 호출이나 인라인이 강제되어야 하는 상황이라면 컴파일 에러가 나요.never_inline— 호출이 인라인되지 않음을 보장해요. 인라인이 강제되는 상황이면 역시 컴파일 에러가 나요.no_suspend— 함수 호출이 suspend되지 않는다고 단언해요. 비동기(async)가 아닌 함수가 async 함수를 호출할 수 있게 해주죠.always_tail— 꼬리 호출 최적화로 생성됨을 보장해요. 불가능하면 컴파일 에러가 나요.always_inline— 호출 지점에서 인라인됨을 보장해요. 불가능하면 컴파일 에러가 나요.compile_time— 호출을 컴파일 타임에 평가해요. 컴파일 타임에 끝낼 수 없으면 컴파일 에러가 나요.
더 알아보기
- 함수 호출과 표현식 호출 문법에 대한 보통의 사용법
@call의 modifier가 활용되는 비동기(async)와 꼬리 호출 최적화