연산자

토파즈의 모든 연산자를 완전 가이드로 학습하세요. 산술, 비교, 논리, 비트, 할당 연산자와 특수 연산자들의 사용법과 우선순위를 마스터합니다.

토파즈는 다양한 연산자를 제공하여 데이터를 조작하고 계산할 수 있습니다. 모든 연산자의 동작 방식과 우선순위를 정확히 이해하는 것이 중요합니다. ⚡

🔢 산술 연산자

기본 산술 연산

// 기본 산술 연산자
let a = 10
let b = 3

let 더하기 = a + b        // 13
let 빼기 = a - b          // 7  
let 곱하기 = a * b        // 30
let 나누기 = a / b        // 3.333...
let 나머지 = a % b        // 1
let 거듭제곱 = a ** b     // 1000

print("더하기: {더하기}")
print("빼기: {빼기}")
print("곱하기: {곱하기}")
print("나누기: {나누기}")
print("나머지: {나머지}")
print("거듭제곱: {거듭제곱}")

부호 연산자

let 양수 = +42     // 42 (명시적 양수)
let 음수 = -42     // -42 (부호 반전)

let 숫자 = 15
let 반전 = -숫자   // -15

print("원래 값: {숫자}")
print("부호 반전: {반전}")

증감 연산자

토파즈 v4에서는 ++/-- 대신 명시적 재할당을 사용합니다.

let mut 카운터 = 5

카운터 = 카운터 + 1
카운터 = 카운터 - 1

function 증가(값: int) -> int { 값 + 1 }
function 감소(값: int) -> int { 값 - 1 }

카운터 = 증가(카운터)
카운터 = 감소(카운터)

print("카운터 최종값: {카운터}")

복합 할당 연산자

let mut= 10

+= 5     // 값 = 값 + 5 = 15
-= 3     // 값 = 값 - 3 = 12  
*= 2     // 값 = 값 * 2 = 24
/= 4     // 값 = 값 / 4 = 6
%= 4     // 값 = 값 % 4 = 2
**= 3    // 값 = 값 ** 3 = 8

print("최종 값: {값}")

🔍 비교 연산자

기본 비교 연산

let x = 10
let y = 20
let z = 10

// 동등성 비교
let 같음 = x == z         // true
let 다름 = x != y         // true

// 크기 비교
let 작음 = x < y          // true
let 작거나같음 = x <= z   // true
let= y > x            // true
let 크거나같음 = z >= x   // true

print("x == z: {같음}")
print("x != y: {다름}")
print("x < y: {작음}")
print("y > x: {큼}")

타입 안전 비교

// Topaz는 타입 안전 비교를 강제
let 정수 = 42
let 실수 = 42.0
let 문자열 = "42"

// 같은 타입끼리만 비교 가능
let 정수비교 = 정수 == 42        // true
let 실수비교 = 실수 == 42.0      // true

// 다른 타입 비교는 명시적 변환 필요
let 타입변환비교 = 정수.toString() == 문자열  // true
let 숫자변환비교 = 정수 == parseInt(문자열)   // true

print("타입 변환 후 비교: {타입변환비교}")

특수 비교 연산자

토파즈 v4에는 <=> 연산자가 없습니다.

🧠 논리 연산자

기본 논리 연산

let= true
let 거짓 = false

// 논리 AND
let AND결과 =&& 거짓     // false
let AND결과2 =&&// true

// 논리 OR  
let OR결과 =|| 거짓      // true
let OR결과2 = 거짓 || 거짓   // false

// 논리 NOT
let NOT결과 = !// false
let NOT결과2 = !거짓        // true

print("AND 결과: {AND결과}")
print("OR 결과: {OR결과}")
print("NOT 결과: {NOT결과}")

단축 평가 (Short-circuit)

function 부작용있는함수() -> bool {
    print("함수가 호출되었습니다!")
    return true
}

// AND 단축 평가 - 첫 번째가 false면 두 번째 실행 안함
let 단축AND = false && 부작용있는함수()  // 함수 호출 안됨

// OR 단축 평가 - 첫 번째가 true면 두 번째 실행 안함
let 단축OR = true || 부작용있는함수()   // 함수 호출 안됨

print("단축 AND: {단축AND}")
print("단축 OR: {단축OR}")

null 병합 연산자

// null 병합 연산자 (??)
let 값1: Option<string> = None
let 값2: Option<string> = Some("기본값")
let 값3 = "대체값"

let 결과1 = 값1 ?? "없음"           // "없음"
let 결과2 = 값2 ?? "없음"           // "기본값"  
let 결과3 = 값1 ?? 값2 ?? 값3       // "기본값"

print("null 병합 결과: {결과1}")

// Option과 함께 사용
let 사용자 = { 이름: "김토파즈", 나이: Some(25) }
let 나이 = match 사용자.나이 { case Some(v) => v; case None => 0 }
print("나이: {나이}")

null 병합 할당 (??=)

현재 값이 None/null일 때만 초기화하는 문장 전용 할당입니다. 표현식 값을 생성하지 않으며 우결합입니다.

let mut 이름: Option<string> = None
이름 ??= Some("guest")      // 이름은 Some("guest")가 됨
이름 ??= Some("override")   // 이미 Some 이므로 변화 없음

// 우결합
a ??= b ??= Some(1)   // a ??= (b ??= Some(1)) 과 동일

🔧 비트/시프트 연산자

토파즈 v4에는 비트/시프트 연산자가 포함되지 않습니다. 또한 >>는 비트 시프트가 아니라 함수 합성 연산자로 예약되어 있습니다(자세한 내용은 아래 함수 합성(>>) 섹션 참고).

🎯 특수 연산자

타입 연산자

토파즈 v4에는 typeofinstanceof가 포함되지 않습니다. 타입 확인이 필요하다면 패턴 매칭이나 라이브러리 제공 유틸리티를 사용하세요.

범위 연산자

// 범위 연산자 (.. 포함, ..< 상한 제외)
let 포함범위 = 1..5       // 1, 2, 3, 4, 5
let 제외범위 = 1..<5      // 1, 2, 3, 4

for i in 포함범위 { print(i) }
for i in 제외범위 { print(i) }

멤버십 연산자 (in)

// 배열/리스트/집합
let ok1 = 3 in [1, 2, 3]                     // true
let ok2 = "a" in Set.of("a", "b")           // true

// 맵 키 (keys 뷰)
let hasId = "id" in 사용자맵.keys              // bool

// 범위
let inside = 5 in 1..10                        // true
let outside = 10 in 1..<10                     // false

스프레드 연산자

토파즈 v4 문법에 포함되지 않습니다.

옵션-안전 옵셔널 체이닝 (?.)

Option<T> 또는 T | null 같은 null 포함 유니온일 때만 파싱되는 연산자입니다. 일반 객체 체이닝은 아닙니다. 일반 멤버 접근은 .을 사용하세요.

let 사용자: Option<{ 이름: string, 프로필: Option<{ 도시: string }> }> =
    Some({ 이름: "Ann", 프로필: Some({ 도시: "Seoul" }) })

let 이름옵션 = 사용자?.이름                 // Option<string>
let 도시옵션 = 사용자?.프로필?.도시         // Option<string>
let 도시     = 사용자?.프로필?.도시 ?? "Unknown"  // string

let 없음사용자: Option<{ 이름: string }> = None
let 기본이름 = 없음사용자?.이름 ?? "guest"       // "guest"

// 내부적으로 Option.map/flatMap 조합으로 환원됩니다
// 사용자?.프로필?.도시  ≃  사용자 |> Option.flatMap(_, u => u.프로필) |> Option.map(_, p => p.도시)

파이프 연산자

// 파이프 연산자 (|>)
let 결과 = 10
    |> (x => x * 2)        // 20
    |> (x => x + 5)        // 25
    |> (x => x.toString())  // "25"

// 함수 체이닝에 유용
let 데이터 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    |> (arr => arr.filter(x => x % 2 == 0))  // [2, 4, 6, 8, 10]
    |> (arr => arr.map(x => x * x))           // [4, 16, 36, 64, 100]
    |> (arr => arr.reduce((a, b) => a + b))  // 220

print("파이프 결과: {결과}")
print("체이닝 결과: {데이터}")

⚡ 연산자 우선순위 (토파즈 v4)

v4
// 높음 → 낮음; 결합성 표시
1) 호출/인덱스/멤버: () [] . ?. (좌결합)
2) 거듭제곱: ** (우결합)
3) 단항: + - ! (우결합)
4) 곱셈/나눗셈/나머지: * / % (좌결합)
5) 덧셈/뺄셈: + - (좌결합)
6) 범위: .. ..< (좌결합)  // 산술보다 낮고 비교보다 높음
7) 비교: < <= > >= == != in (좌결합)
8) 논리 AND: && (좌결합)
9) 논리 OR: || (좌결합)
10) null 병합: ?? (좌결합)
11) 함수 합성: >> (우결합)
12) 파이프라인: |> (좌결합)
13) 할당: = …, ??= (우결합)

// 합성 vs 파이프라인
let h = f >> g
let x = 입력 |> h          // 입력 |> (f >> g) 와 동일

함수 합성 (>>)

let 정규화 = trim >> toLowerCase >> collapseSpaces
print(정규화("  Hello   WORLD  "))  // "hello world"

🔄 연산자 오버로딩

사용자 정의 타입 연산자

// 구조체에 연산자 구현
struct 벡터 {
    x: float,
    y: float
}

impl 벡터 {
    // + 연산자 오버로딩
    function +(other: 벡터) -> 벡터 {
        return 벡터 { x: self.x + other.x, y: self.y + other.y }
    }
    
    // * 연산자 오버로딩 (스칼라 곱)
    function *(scalar: float) -> 벡터 {
        return 벡터 { x: self.x * scalar, y: self.y * scalar }
    }
    
    // == 연산자 오버로딩
    function ==(other: 벡터) -> bool {
        return self.x == other.x && self.y == other.y
    }
    
    // 문자열 변환
    function toString() -> string {
        return "벡터({self.x}, {self.y})"
    }
}

// 사용 예제
let 벡터1 = 벡터 { x: 3.0, y: 4.0 }
let 벡터2 = 벡터 { x: 1.0, y: 2.0 }

let= 벡터1 + 벡터2             // 벡터(4.0, 6.0)
let 배수 = 벡터1 * 2.0            // 벡터(6.0, 8.0)
let 같은가 = 벡터1 == 벡터2        // false

print("벡터 합: {합}")
print("벡터 배수: {배수}")
print("벡터 같음: {같은가}")

🛡️ 안전한 연산자 사용법

1. 오버플로우 처리

// 체크된 산술 연산
let 큰수1 = 2147483647  // int 최대값
let 큰수2 = 1

// 안전한 덧셈 (오버플로우 검사)
match 큰수1.checkedAdd(큰수2) {
    case Some(결과) => print("안전한 덧셈: {결과}")
    case None => print("오버플로우 발생!")
}

// 포화 연산 (최대/최소값으로 클램핑)
let 포화덧셈 = 큰수1.saturatingAdd(큰수2)  // int 최대값 유지
print("포화 덧셈: {포화덧셈}")

2. 0으로 나누기 방지

function 안전한나누기(분자: float, 분모: float) -> Result<float, string> {
    if 분모 == 0.0 {
        return Err("0으로 나눌 수 없습니다")
    }
    return Ok(분자 / 분모)
}

// 사용 예제
match 안전한나누기(10.0, 0.0) {
    case Ok(결과) => print("나누기 결과: {결과}")
    case Err(오류) => print("오류: {오류}")
}

3. 타입 안전성

// 명시적 타입 변환으로 안전성 확보
let 문자열숫자 = "123"
let 실제숫자 = match parseInt(문자열숫자) {
    case Ok(숫자) => 숫자
    case Err(_) => {
        print("숫자 변환 실패")
        0  // 기본값
    }
}

let 결과 = 실제숫자 + 100
print("안전한 계산 결과: {결과}")

📊 성능 최적화 팁

1. 비싼 연산 최적화

// 거듭제곱 대신 곱셈 사용 (작은 지수)
let 제곱 =*// x ** 2 대신
let 세제곱 =**// x ** 3 대신

// 나누기 대신 곱셈 사용
let 반값 =* 0.5          // 값 / 2 대신

// 모듈로 연산 최적화 (2의 거듭제곱)
let 나머지 =& 7          // 값 % 8 대신 (8 = 2^3)

2. 단축 평가 활용

// 비싼 함수 호출을 뒤로
let 결과 = 간단한조건() && 복잡한함수()

// null 체크 최적화
let= 객체?.속성?.하위속성 ?? 기본값

토파즈의 연산자들을 정확히 이해하고 적절히 활용하면 효율적이고 안전한 코드를 작성할 수 있습니다! 연산자 우선순위와 타입 안전성을 항상 염두에 두세요. 🎯