토파즈 문법 기초

코드가 시가 되는 언어 토파즈의 문법을 마스터하세요. 현대적이고 표현력 풍부한 문법으로 아름다운 코드를 작성하는 방법을 배워보세요.

"코드가 시가 되는 언어" 토파즈의 문법은 최소한의 코드로 최대한의 표현력을 추구합니다. 이 가이드에서 토파즈만의 아름다운 문법을 마스터해보세요. 🌟

🎯 핵심 철학

"Write Less, Express More"

복잡한 로직도 간결하고 읽기 쉽게 표현할 수 있습니다.

글로벌 문법, 로컬 표현

  • 키워드: 영어로 통일 (function, let, match, case)
  • 식별자: 한글, 영어, 이모지 자유롭게 사용 가능

모든 것은 표현식

if, match, for, try 등 모든 구문이 값을 반환합니다.

📝 기본 문법

변수 선언

// 불변 변수 (기본)
let 이름 = "김토파즈"
let 나이 = 25
let 활성화 = true

// 가변 변수
mut let 점수 = 85
점수 = 90  // 변경 가능

// 타입 명시 (선택적)
let 거리: float = 3.14
let 사용자들: Array<string> = ["김철수", "박영희"]

null 병합 할당 (??=)

대상 값이 None/null일 때만 초기화하는 문장 전용 연산자입니다.

let mut 이름: Option<string> = None
이름 ??= Some("guest")

함수 정의

// 기본 함수
function 인사하기(이름: string) -> string {
    "안녕하세요, {이름}님!"
}

// 기본값 매개변수
function 계산하기(x: int, y: int = 10) -> int {
    x + y
}

// 다중 반환값
function 좌표계산() -> (int, int) {
    (100, 200)
}

// 고차 함수
function 변환(데이터: Array<int>, 함수: (int) -> int) -> Array<int> {
    데이터.map(함수)
}

조건문

// if 표현식 (값을 반환)
let 메시지 = if 나이 >= 20 {
    "성인입니다"
} else if 나이 >= 13 {
    "청소년입니다"
} else {
    "어린이입니다"
}

// 삼항 연산자 스타일
let 상태 = if 온라인 { "접속중" } else { "오프라인" }

패턴 매칭

// 기본 매칭
let 결과 = match 값 {
    case 1 => "하나"
    case 2 => "둘"
    case 3 => "셋"
    case _ => "기타"
}

// 범위 매칭
let 등급 = match 점수 {
    case 90..100 => "A"
    case 80..<90 => "B"
    case 70..<80 => "C"
    case _ => "F"
}

// 구조 매칭
let 할인율 = match 고객 {
    case { 등급: "VIP", 구매액 } if 구매액 > 1000000 => 0.3
    case { 등급: "VIP" } => 0.2
    case { 가입일 } if 오늘 - 가입일 > 365일 => 0.1
    case _ => 0.0
}

#### 리스트 패턴

```rust
match xs {
  case [head, ..tail] => 사용(head, tail)
  case [..init, last] => 마지막사용(init, last)
  case [a, .., z] => 양끝사용(a, z)
  case [x, y, ..rest] if rest.length > 0 => 처리(x, y, rest)
}

엔드투엔드 예시(가드 + 중첩 리스트 패턴):

let 설명 = match 숫자들 {
  case [] => "빈 리스트"
  case [단일] => "하나"
  case [첫, .., 끝] if<=> "오름차순 경향"
  case [첫, ..중간, 끝] => "양끝 {첫}..{끝}, 중간={중간.length}"
}
## 🌊 파이프라인 연산

### 기본 파이프라인

```rust
// 데이터가 흐르는 듯한 표현
let 결과 = 원본데이터
    |> 정규화()
    |> 필터링(x => x > 0)
    |> 맵핑(x => x * 2)
    |> 정렬()

메서드 체이닝과 혼용

let 처리된문자열 = "hello world"
    .split(" ")
    |> 각각(단어 => 단어.첫글자대문자())
    .join(" ")
    |> 추가("!", _)
// 결과: "Hello World!"

파이프 슈거

v4

파이프 오른쪽에서 간결한 표기법을 사용할 수 있습니다.


  |> .length                  // 속성 슈거: (x => x.length)
  |> replace("foo", _, "bar") // 메서드 슈거: (x => replace("foo", x, "bar"))

// 여러 개의 _ 는 가장 가까운 호출에 왼쪽부터 순서대로 바인딩
|> format("id=", _, ":", _)

🧠 타입 시스템

타입 추론

// 타입이 자동으로 추론됩니다
let 숫자 = 42              // int
let 문자열 = "안녕"         // string
let 배열 = [1, 2, 3, 4]    // Array<int>
let 구조체 = {             // { 이름: string, 나이: int }
    이름: "김토파즈",
    나이: 25
}

리터럴 타입

// 정확한 값으로 타입 제한
type 신호등 = "빨강" | "노랑" | "초록"
type 주사위 = 1 | 2 | 3 | 4 | 5 | 6
type 상태코드 = 200 | 404 | 500

function 신호처리(색: 신호등) {
    match 색 {
        case "빨강" => 정지()
        case "노랑" => 주의()
        case "초록" => 출발()
        // 모든 경우를 처리했는지 컴파일러가 확인!
    }
}

유니온 타입

type 사용자입력 = string | int | null

function 처리(입력: 사용자입력) -> string {
    match 입력 {
        case s: string => "문자열: {s}"
        case n: int => "숫자: {n}"
        case null => "입력 없음"
    }
}

🔁 반복문

for 루프 (표현식)

// 범위 반복
for i in 1..10 {
    print("숫자: {i}")
}

// 배열 반복
for 항목 in ["사과", "바나나", "체리"] {
    print("과일: {항목}")
}

// 인덱스와 함께
for (인덱스, 값) in 데이터.enumerate() {
    print("{인덱스}: {값}")
}

// for도 값을 반환!
let 제곱수들 = for x in 1..5 { x * x }  // [1, 4, 9, 16]

by를 사용한 범위 스텝

v4
// 증가 스텝
for i in 0..10 by 2 { print(i) }        // 0,2,4,6,8,10

// 감소 스텝 (음수 stride)
for i in 10..0 by -3 { print(i) }       // 10,7,4,1

// 날짜/시간 스텝 (라이브러리 기간 단위)
for day in 시작일..종료일 by 1.day { 일정.추가(day) }

while 루프

mut let 카운터 = 0
while 카운터 < 10 {
    print("카운터: {카운터}")
    카운터 = 카운터 + 1
}

📚 컬렉션

배열

// 기본 배열
let 숫자들 = [1, 2, 3, 4, 5]
let 과일들 = ["사과", "바나나", "체리"]

// 배열 메서드
let 큰수들 = 숫자들.filter(x => x > 2)  // [3, 4, 5]
let 제곱들 = 숫자들.map(x => x * x)     // [1, 4, 9, 16, 25]
let 합계 = 숫자들.reduce(0, +)          // 15

멤버십 (in)

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

// 맵 키
let hasId = "id" in 사용자맵.keys

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

객체/구조체

// 객체 리터럴
let 사용자 = {
    이름: "김토파즈",
    나이: 25,
    이메일: "topaz@example.com"
}

// 구조체 정의
struct 사용자 {
    이름: string,
    나이: int,
    이메일: string
}

// 구조체 인스턴스
let 새사용자 = 사용자 {
    이름: "박루비",
    나이: 30,
    이메일: "ruby@example.com"
}

레코드 업데이트 리터럴

v4

불변으로 얕은 복사를 한 뒤 선택한 필드만 갱신합니다.

let 사용자 = { 이름: "Alice", 나이: 20, 도시: "Seoul" }
let 갱신 = 사용자{ 나이: 사용자.나이 + 1, 도시: "Busan" }
// { 이름: "Alice", 나이: 21, 도시: "Busan" }

🎭 문자열 템플릿

기본 보간

let 이름 = "토파즈"
let 나이 = 25
let 인사 = "안녕하세요, {이름}님! 나이가 {나이}세이시군요."

태그드 템플릿

v4

표준 태그와 안전/메타 보존:

let 경로 = p"/home/{사용자}/docs/{파일명}"        // 경로 정규화
let 패턴 = r"^[a-z0-9_]+$"                         // 정규식 이스케이프 간소화
let 명령 = sh"grep {패턴} {파일}"                  // 안전 셸 템플릿(실행 정책 적용)

// SQL: 보간은 항상 파라미터 바인딩으로 처리 (직접 문자열 삽입 금지)
let 쿼리 = sql"SELECT * FROM users WHERE age > {나이} AND city = {도시}"

⚡ 비동기 처리

자동 비동기

// I/O는 자동으로 비동기 처리되지만 동기처럼 작성!
function 사용자정보가져오기(id: int) -> 사용자 {
    let 기본정보 = API.사용자조회(id)      // 자동 비동기 처리
    let 프로필 = API.프로필조회(id)        // 자동 비동기 처리
    
    사용자 {
        기본정보: 기본정보,
        프로필: 프로필
    }
}

병렬 실행

// 여러 작업을 병렬로 실행
let 결과 = concurrent {
    날씨: 날씨API.현재날씨("서울"),
    환율: 환율API.달러환율(),
    뉴스: 뉴스API.헤드라인(5개)
}

🛡️ 에러 처리

Result 타입

function 안전한나누기(a: int, b: int) -> Result<int, string> {
    if b == 0 {
        Err("0으로 나눌 수 없습니다")
    } else {
        Ok(a / b)
    }
}

// ? 연산자로 간단하게
function 복잡한계산(x: int) -> Result<int, string> {
    let 결과1 = 안전한나누기(x, 2)?
    let 결과2 = 안전한나누기(결과1, 3)?
    Ok(결과2 * 10)
}

try 표현식

let 설정 = try {
    파일읽기("config.json")?
} else {
    // 기본값 반환
    { 테마: "다크", 언어: "한국어" }
}

🎨 고급 기능

부분 적용

let 더하기10 = 더하기(10, _)
let 결과 = [1, 2, 3].map(더하기10)  // [11, 12, 13]

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

v4

좌변이 Option<T> 또는 T | null 같은 null 포함 유니온일 때만 사용하는 연산자입니다. 좌→우로 단락 평가하며 내부적으로 Option.map/flatMap으로 환원됩니다.

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

let 이름옵션 = 사용자?.이름
let 도시옵션 = 사용자?.프로필?.도시

// ??와 조합해 기본값 제공
let 도시 = 사용자?.프로필?.도시 ?? "Unknown"

// 일반 객체 체이닝이 아닙니다 — Option 이 아닌 값에는 `.` 사용
let 일반 = { 이름: "Jo" }
let ok = 일반.이름

동등한 map/flatMap 표현:

// 사용자?.프로필?.도시
let 함수형 = 사용자
  |> Option.flatMap(_, u => u.프로필)
  |> Option.map(_, p => p.도시)

매크로

// 반복 실행 매크로
macro 반복실행(횟수: int) {
    for i in 1..횟수 {
        print("실행 {i}/{횟수}")
        yield  // 사용자 코드 실행
    }
}

반복실행(3) {
    중요한작업()
}

🔧 실용적 예제

웹 API 호출

let 사용자데이터 = fetch("https://api.example.com/users/1")
    |> json()
    |> (data => {
        이름: data.name,
        이메일: data.email,
        가입일: Date.parse(data.created_at)
    })

데이터 처리 파이프라인

let 분석결과 = CSV.읽기("sales.csv")
    |> 필터(행 =>.매출 > 1000000)
    |> 그룹화(행 =>.지역)
    |> 집계(그룹 => {
        지역: 그룹.키,
        총매출: 그룹..합계(행 =>.매출),
        평균매출: 그룹..평균(행 =>.매출)
    })
    |> 정렬(내림차순:=>.총매출)

🎯 다음 단계

이제 토파즈의 기본 문법을 마스터했습니다! 다음으로 학습할 내용:

토파즈와 함께 코딩이 시가 되는 경험을 계속해보세요!