변수와 스코프

토파즈에서 변수 선언, 스코프 관리, 가변성 제어를 마스터하세요. let, let mut, const의 차이점과 렉시컬 스코핑, 클로저의 동작 원리를 배워보세요.

변수와 스코프는 프로그래밍의 핵심입니다. 토파즈는 현대적이고 안전한 변수 시스템을 제공하여 버그를 줄이고 코드의 명확성을 높입니다. 🎯

🔧 변수 선언

let - 불변 변수 (기본)

// 기본적으로 모든 변수는 불변입니다
let 이름 = "김토파즈"
let 나이 = 25
let 활성화됨 = true

// 한 번 정의된 후에는 변경할 수 없습니다
// 이름 = "다른이름"  // 컴파일 에러!

let mut - 가변 변수

// 값을 변경해야 할 때는 let mut 사용
let mut 점수 = 100
let mut 메시지 = "초기 메시지"

// 값 변경 가능
점수 = 95
메시지 = "업데이트된 메시지"

print("현재 점수: {점수}")  // "현재 점수: 95"

const - 컴파일 타임 상수

// 컴파일 시점에 결정되는 상수
const MAX_SIZE: int = 1000
const APP_NAME: string = "Topaz Calculator"
const PI: float = 3.141592653589793

// 다른 파일에서도 사용 가능한 전역 상수
const 기본설정 = {
    언어: "한국어",
    테마: "다크",
    자동저장: true
}

🎯 타입 추론과 명시적 타입

// 타입 추론 (권장)
let 자동추론숫자 = 42           // int
let 자동추론문자열 = "Hello"     // string
let 자동추론배열 = [1, 2, 3]    // [int]

// 명시적 타입 (필요할 때)
let 명시적숫자: int = 42
let 명시적문자열: string = "Hello"
let 명시적배열: [int] = [1, 2, 3]

// 복잡한 경우 타입 명시가 도움됨
let 사용자데이터: { 이름: string, 나이: int } = {
    이름: "김개발자",
    나이: 30
}

🏠 스코프 규칙

전역 스코프

// 파일 최상위 레벨 - 전역 스코프
let 전역변수 = "모든 곳에서 접근 가능"
const 전역상수 = 100

function 어디서든사용() {
    print(전역변수)  // 접근 가능
    print(전역상수)  // 접근 가능
}

함수 스코프

function 계산기(a: int, b: int) -> int {
    // 함수 매개변수도 함수 스코프에 속함
    let 결과 = a + b        // 함수 스코프
    let mut 임시값 = a * 2      // 함수 스코프
    
    print("결과: {결과}")
    return 결과
}

// print(결과)  // 에러! 함수 밖에서 접근 불가

블록 스코프

function 스코프예제() {
    let 외부변수 = "바깥"
    
    if true {
        let 내부변수 = "안쪽"        // 블록 스코프
        let mut 블록가변 = 10            // 블록 스코프
        
        print(외부변수)              // 접근 가능 (상위 스코프)
        print(내부변수)              // 접근 가능 (같은 스코프)
    }
    
    print(외부변수)                  // 접근 가능
    // print(내부변수)               // 에러! 블록 밖에서 접근 불가
}

루프 스코프

// for 루프의 변수는 루프 스코프를 가짐
for i in 0..5 {
    let 루프내변수 = i * 2
    print("i: {i}, 값: {루프내변수}")
}

// print(i)  // 에러! 루프 밖에서 접근 불가

// while 루프도 마찬가지
let mut 카운터 = 0
while 카운터 < 3 {
    let 임시 = 카운터 + 10
    print(임시)
    카운터 += 1
}

🔒 섀도잉 (Variable Shadowing)

let 이름 = "김토파즈"

function 섀도잉예제() {
    let 이름 = "박개발자"        // 전역 이름을 가림 (섀도잉)
    print("함수 내: {이름}")     // "함수 내: 박개발자"
    
    {
        let 이름 = "이디자이너"   // 함수의 이름을 가림
        print("블록 내: {이름}")  // "블록 내: 이디자이너"
    }
    
    print("블록 후: {이름}")     // "블록 후: 박개발자"
}

print("전역: {이름}")           // "전역: 김토파즈"
섀도잉예제()

🌟 클로저와 스코프

function 카운터생성기(초기값: int) -> function() -> int {
    let mut 개수 = 초기값           // 클로저에 캡처됨
    
    return function() -> int {
        개수 += 1               // 상위 스코프의 변수 접근
        return 개수
    }
}

let 카운터1 = 카운터생성기(0)
let 카운터2 = 카운터생성기(100)

print(카운터1())  // 1
print(카운터1())  // 2
print(카운터2())  // 101
print(카운터1())  // 3

🎭 패턴 매칭과 변수

let 사용자 = {
    이름: "김토파즈",
    나이: 28,
    직업: "개발자"
}

// 구조 분해로 새 변수 생성
let { 이름, 나이 } = 사용자
print("이름: {이름}, 나이: {나이}")

// match에서 변수 바인딩
match 사용자.나이 {
    case 나이 if 나이 < 20 => print("학생일 가능성이 높음")
    case 나이 if 나이 < 30 => print("청년층")
    case 나이 => print("경력자: {나이}세")
}

// 배열 패턴 매칭
let 점수들 = [95, 87, 92, 88]
match 점수들 {
    case [첫번째, 두번째, ...나머지] => {
        print("첫 번째: {첫번째}")
        print("두 번째: {두번째}")
        print("나머지: {나머지}")
    }
}

⚡ 고급 스코프 패턴

IIFE (즉시 실행 함수)

// 즉시 실행 함수로 스코프 격리
let 결과 = (function() -> int {
    let 임시계산 = 10 * 20
    let 보정값 = 50
    return 임시계산 + 보정값
})()

print(결과)  // 250
// 임시계산, 보정값은 접근 불가

모듈 스코프

// math_utils.tpz 파일
export const PI = 3.141592653589793
export let 기본정밀도 = 6

export function 원넓이(반지름: float) -> float {
    let 내부계산 = 반지름 * 반지름    // 모듈 내부에서만 접근 가능
    return PI * 내부계산
}

// main.tpz 파일
import { PI, 원넓이 } from "./math_utils"

print(PI)            // 접근 가능
print(원넓이(5.0))   // 접근 가능
// print(내부계산)   // 에러! 모듈 내부 변수는 접근 불가

🛡️ 베스트 프랙티스

1. 기본적으로 불변 사용

// 좋은 예: 기본적으로 let 사용
let 설정 = {
    테마: "다크",
    언어: "한국어"
}

// 필요할 때만 let mut 사용
let mut 진행상태 = "시작"
진행상태 = "진행중"
진행상태 = "완료"

2. 의미있는 변수명

// 나쁜 예
let a = 사용자목록.length()
let b = a * 0.1

// 좋은 예  
let 총사용자수 = 사용자목록.length()
let 수수료 = 총사용자수 * 0.1

3. 스코프 최소화

function 데이터처리(원본데이터: [int]) -> [int] {
    let 결과 = []
    
    for 항목 in 원본데이터 {
        // 루프 내에서만 필요한 변수는 루프 내에서 선언
        let 변환된값 = 항목 * 2 + 1
        let 검증된값 = if 변환된값 > 0 { 변환된값 } else { 0 }
        
        결과.push(검증된값)
    }
    
    return 결과
}

🔍 디버깅 팁

// 스코프 디버깅을 위한 유틸리티
function 스코프정보출력() {
    let 지역변수 = "local"
    
    print("현재 함수의 변수들:")
    print("- 지역변수: {지역변수}")
    
    // 전역 변수 접근
    if defined(전역변수) {
        print("- 전역변수 접근 가능")
    }
}

// 변수 존재 여부 확인
function 안전한접근(변수명: string) {
    if defined(변수명) {
        print("{변수명}가 정의되어 있습니다")
    } else {
        print("{변수명}가 정의되지 않았습니다")
    }
}

토파즈의 변수와 스코프 시스템은 안전성명확성을 동시에 제공합니다. 불변성을 기본으로 하되 필요할 때 가변성을 허용하고, 명확한 스코프 규칙으로 예측 가능한 코드를 작성할 수 있습니다. 🚀