1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2024-12-14 22:15:54 +02:00
comprehensive-rust/po/ko.po
Martin Geisler 98f5f9a88f
Revert "Fix typo: missing n in unknown" (#1347)
Reverts google/comprehensive-rust#1344.

The edit to the Markdown file has been kept since we _do_ want to fix
the typo!
2023-10-11 11:47:04 +00:00

27734 lines
910 KiB
Plaintext

msgid ""
msgstr ""
"Project-Id-Version: [한국어]Comprehensive Rust 🦀\n"
"POT-Creation-Date: 2023-09-24\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ko\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.3.2\n"
#: src/SUMMARY.md:4 src/index.md:1
msgid "Welcome to Comprehensive Rust 🦀"
msgstr "Comprehensive Rust에 오신 것을 환영합니다 🦀"
#: src/SUMMARY.md:5 src/running-the-course.md:1
msgid "Running the Course"
msgstr "강의 진행"
#: src/SUMMARY.md:6 src/running-the-course/course-structure.md:1
msgid "Course Structure"
msgstr "강의 구성"
#: src/SUMMARY.md:7 src/running-the-course/keyboard-shortcuts.md:1
msgid "Keyboard Shortcuts"
msgstr "단축키"
#: src/SUMMARY.md:8 src/running-the-course/translations.md:1
msgid "Translations"
msgstr "다른 언어들"
#: src/SUMMARY.md:9 src/cargo.md:1
msgid "Using Cargo"
msgstr "카고 사용하기"
#: src/SUMMARY.md:10
msgid "Rust Ecosystem"
msgstr "러스트 생태계"
#: src/SUMMARY.md:11
msgid "Code Samples"
msgstr "코드 샘플"
#: src/SUMMARY.md:12
msgid "Running Cargo Locally"
msgstr "카고(Cargo) 수행하기"
#: src/SUMMARY.md:15
msgid "Day 1: Morning"
msgstr "1일차 오전"
#: src/SUMMARY.md:19 src/SUMMARY.md:76 src/SUMMARY.md:130 src/SUMMARY.md:187
#: src/SUMMARY.md:213 src/SUMMARY.md:263
msgid "Welcome"
msgstr "개요"
#: src/SUMMARY.md:20 src/welcome-day-1/what-is-rust.md:1
msgid "What is Rust?"
msgstr "러스트란?"
#: src/SUMMARY.md:21 src/hello-world.md:1
msgid "Hello World!"
msgstr "Hello World!"
#: src/SUMMARY.md:22 src/hello-world/small-example.md:1
msgid "Small Example"
msgstr "작은 예제"
#: src/SUMMARY.md:23 src/why-rust.md:1
msgid "Why Rust?"
msgstr "러스트를 써야하는 이유"
#: src/SUMMARY.md:24 src/why-rust/compile-time.md:1
msgid "Compile Time Guarantees"
msgstr "컴파일 시 보장되는 것들"
#: src/SUMMARY.md:25 src/why-rust/runtime.md:1
msgid "Runtime Guarantees"
msgstr "런타임 시 보장되는 것들"
#: src/SUMMARY.md:26 src/why-rust/modern.md:1
msgid "Modern Features"
msgstr "현대적인 특징"
#: src/SUMMARY.md:27 src/basic-syntax.md:1
msgid "Basic Syntax"
msgstr "기본 문법"
#: src/SUMMARY.md:28 src/basic-syntax/scalar-types.md:1
msgid "Scalar Types"
msgstr "스칼라 타입"
#: src/SUMMARY.md:29 src/basic-syntax/compound-types.md:1
msgid "Compound Types"
msgstr "복합 타입"
#: src/SUMMARY.md:30 src/basic-syntax/references.md:1
msgid "References"
msgstr "참조"
#: src/SUMMARY.md:31 src/basic-syntax/references-dangling.md:1
msgid "Dangling References"
msgstr "허상(dangling) 참조"
#: src/SUMMARY.md:32 src/basic-syntax/slices.md:1
msgid "Slices"
msgstr "슬라이스"
#: src/SUMMARY.md:33
msgid "String vs str"
msgstr "String과 str"
#: src/SUMMARY.md:34 src/basic-syntax/functions.md:1
msgid "Functions"
msgstr "함수"
#: src/SUMMARY.md:35 src/basic-syntax/rustdoc.md:1
msgid "Rustdoc"
msgstr "Rustdoc"
#: src/SUMMARY.md:36 src/SUMMARY.md:83 src/basic-syntax/methods.md:1
#: src/methods.md:1
msgid "Methods"
msgstr "메서드"
#: src/SUMMARY.md:37
msgid "Overloading"
msgstr "오버로딩"
#: src/SUMMARY.md:38 src/SUMMARY.md:67 src/SUMMARY.md:91 src/SUMMARY.md:121
#: src/SUMMARY.md:150 src/SUMMARY.md:179 src/SUMMARY.md:206 src/SUMMARY.md:227
#: src/SUMMARY.md:255 src/SUMMARY.md:277 src/SUMMARY.md:298
#: src/exercises/android/morning.md:1 src/exercises/bare-metal/morning.md:1
#: src/exercises/bare-metal/afternoon.md:1
#: src/exercises/concurrency/morning.md:1
#: src/exercises/concurrency/afternoon.md:1
msgid "Exercises"
msgstr "연습문제"
#: src/SUMMARY.md:39 src/exercises/day-1/implicit-conversions.md:1
msgid "Implicit Conversions"
msgstr "묵시적 형변환"
#: src/SUMMARY.md:40
msgid "Arrays and for Loops"
msgstr "배열과 for 반복문"
#: src/SUMMARY.md:42
msgid "Day 1: Afternoon"
msgstr "1일차 오후"
#: src/SUMMARY.md:44 src/basic-syntax/variables.md:1
msgid "Variables"
msgstr "변수"
#: src/SUMMARY.md:45 src/basic-syntax/type-inference.md:1
msgid "Type Inference"
msgstr "타입 추론"
#: src/SUMMARY.md:46
msgid "static & const"
msgstr "정적변수(static)와 상수(const)"
#: src/SUMMARY.md:47 src/basic-syntax/scopes-shadowing.md:1
msgid "Scopes and Shadowing"
msgstr "범위(Scopes)와 쉐도잉(Shadowing)"
#: src/SUMMARY.md:48 src/memory-management.md:1
msgid "Memory Management"
msgstr "메모리 관리"
#: src/SUMMARY.md:49
msgid "Stack vs Heap"
msgstr "스택(Stack)과 힙(Heap)"
#: src/SUMMARY.md:50
msgid "Stack Memory"
msgstr "스택 메모리"
#: src/SUMMARY.md:51 src/memory-management/manual.md:1
msgid "Manual Memory Management"
msgstr "수동 메모리 관리"
#: src/SUMMARY.md:52 src/memory-management/scope-based.md:1
msgid "Scope-Based Memory Management"
msgstr "범위기반 메모리 관리"
#: src/SUMMARY.md:53
msgid "Garbage Collection"
msgstr "가비지 컬렉션"
#: src/SUMMARY.md:54
msgid "Rust Memory Management"
msgstr "러스트의 메모리 관리"
#: src/SUMMARY.md:55 src/memory-management/comparison.md:1
msgid "Comparison"
msgstr "비교"
#: src/SUMMARY.md:56 src/ownership.md:1
msgid "Ownership"
msgstr "소유권"
#: src/SUMMARY.md:57 src/ownership/move-semantics.md:1
msgid "Move Semantics"
msgstr "Move 문법"
#: src/SUMMARY.md:58 src/ownership/moved-strings-rust.md:1
msgid "Moved Strings in Rust"
msgstr "러스트에서의 문자열 이동"
#: src/SUMMARY.md:59
msgid "Double Frees in Modern C++"
msgstr "Modern C++에서 이중해제 문제"
#: src/SUMMARY.md:60 src/ownership/moves-function-calls.md:1
msgid "Moves in Function Calls"
msgstr "함수 호출에서의 이동(Move)"
#: src/SUMMARY.md:61 src/ownership/copy-clone.md:1
msgid "Copying and Cloning"
msgstr "복사와 복제"
#: src/SUMMARY.md:62 src/ownership/borrowing.md:1
msgid "Borrowing"
msgstr "빌림"
#: src/SUMMARY.md:63 src/ownership/shared-unique-borrows.md:1
msgid "Shared and Unique Borrows"
msgstr "공유와 고유 빌림"
#: src/SUMMARY.md:64 src/ownership/lifetimes.md:1
msgid "Lifetimes"
msgstr "수명"
#: src/SUMMARY.md:65 src/ownership/lifetimes-function-calls.md:1
msgid "Lifetimes in Function Calls"
msgstr "함수 호출에서의 수명"
#: src/SUMMARY.md:66 src/ownership/lifetimes-data-structures.md:1
msgid "Lifetimes in Data Structures"
msgstr "구조체에서의 수명"
#: src/SUMMARY.md:68 src/exercises/day-1/book-library.md:1
msgid "Storing Books"
msgstr "책 저장하기"
#: src/SUMMARY.md:69 src/exercises/day-1/iterators-and-ownership.md:1
msgid "Iterators and Ownership"
msgstr "반복자와 소유권"
#: src/SUMMARY.md:72
msgid "Day 2: Morning"
msgstr "2일차 오전"
#: src/SUMMARY.md:77 src/structs.md:1
msgid "Structs"
msgstr "구조체"
#: src/SUMMARY.md:78 src/structs/tuple-structs.md:1
msgid "Tuple Structs"
msgstr "튜플"
#: src/SUMMARY.md:79 src/structs/field-shorthand.md:1
msgid "Field Shorthand Syntax"
msgstr "필드 할당 단축 문법"
#: src/SUMMARY.md:80 src/enums.md:1
msgid "Enums"
msgstr "열거형"
#: src/SUMMARY.md:81 src/enums/variant-payloads.md:1
msgid "Variant Payloads"
msgstr "데이터를 포함하는 열거형(Variant Payloads)"
#: src/SUMMARY.md:82 src/enums/sizes.md:1
msgid "Enum Sizes"
msgstr "열거형의 크기"
#: src/SUMMARY.md:84 src/methods/receiver.md:1
msgid "Method Receiver"
msgstr "메서드 리시버(Receiver)"
#: src/SUMMARY.md:85 src/SUMMARY.md:161 src/SUMMARY.md:276
#: src/methods/example.md:1 src/concurrency/shared_state/example.md:1
msgid "Example"
msgstr "예제"
#: src/SUMMARY.md:86 src/pattern-matching.md:1
msgid "Pattern Matching"
msgstr "패턴 매칭"
#: src/SUMMARY.md:87 src/pattern-matching/destructuring-enums.md:1
msgid "Destructuring Enums"
msgstr "열거형 분해(역구조화)"
#: src/SUMMARY.md:88 src/pattern-matching/destructuring-structs.md:1
msgid "Destructuring Structs"
msgstr "구조체 분해(역구조화)"
#: src/SUMMARY.md:89 src/pattern-matching/destructuring-arrays.md:1
msgid "Destructuring Arrays"
msgstr "배열 분해(역구조화)"
#: src/SUMMARY.md:90 src/pattern-matching/match-guards.md:1
msgid "Match Guards"
msgstr "매치 가드"
#: src/SUMMARY.md:92 src/exercises/day-2/health-statistics.md:1
msgid "Health Statistics"
msgstr "건강상태 모니터링 시스템"
#: src/SUMMARY.md:93 src/exercises/day-2/solutions-morning.md:3
msgid "Points and Polygons"
msgstr "점과 다각형"
#: src/SUMMARY.md:95
msgid "Day 2: Afternoon"
msgstr "2일차 오후"
#: src/SUMMARY.md:97 src/SUMMARY.md:290 src/control-flow.md:1
msgid "Control Flow"
msgstr "흐름 제어"
#: src/SUMMARY.md:98 src/control-flow/blocks.md:1
msgid "Blocks"
msgstr "블록"
#: src/SUMMARY.md:99
msgid "if expressions"
msgstr "if 표현식"
#: src/SUMMARY.md:100
msgid "if let expressions"
msgstr "if let 표현식"
#: src/SUMMARY.md:101
msgid "while expressions"
msgstr "while 표현식"
#: src/SUMMARY.md:102
msgid "while let expressions"
msgstr "while let 표현식"
#: src/SUMMARY.md:103
msgid "for expressions"
msgstr "for 표현식"
#: src/SUMMARY.md:104
msgid "loop expressions"
msgstr "loop 표현식"
#: src/SUMMARY.md:105
msgid "match expressions"
msgstr "match 표현식"
#: src/SUMMARY.md:106
msgid "break & continue"
msgstr "break와 continue"
#: src/SUMMARY.md:107 src/std.md:1
msgid "Standard Library"
msgstr "표준 라이브러리"
#: src/SUMMARY.md:108
msgid "Option and Result"
msgstr "Option과 Result"
#: src/SUMMARY.md:109 src/std/string.md:1
msgid "String"
msgstr "String"
#: src/SUMMARY.md:110
msgid "Vec"
msgstr "Vec"
#: src/SUMMARY.md:111
msgid "HashMap"
msgstr "HashMap"
#: src/SUMMARY.md:112
msgid "Box"
msgstr "Box"
#: src/SUMMARY.md:113
msgid "Recursive Data Types"
msgstr "재귀적 자료구조"
#: src/SUMMARY.md:114 src/std/box-niche.md:1
msgid "Niche Optimization"
msgstr "니치(틈새) 최적화(Niche Optimization)"
#: src/SUMMARY.md:115
msgid "Rc"
msgstr "Rc"
#: src/SUMMARY.md:116
msgid "Cell/RefCell"
msgstr "Cell과 RefCell"
#: src/SUMMARY.md:117 src/modules.md:1
msgid "Modules"
msgstr "모듈"
#: src/SUMMARY.md:118 src/modules/visibility.md:1
msgid "Visibility"
msgstr "가시성"
#: src/SUMMARY.md:119 src/modules/paths.md:1
msgid "Paths"
msgstr "경로"
#: src/SUMMARY.md:120 src/modules/filesystem.md:1
msgid "Filesystem Hierarchy"
msgstr "파일시스템 계층"
#: src/SUMMARY.md:122 src/exercises/day-2/luhn.md:1
#: src/exercises/day-2/solutions-afternoon.md:3
msgid "Luhn Algorithm"
msgstr "룬 알고리즘"
#: src/SUMMARY.md:123 src/exercises/day-2/strings-iterators.md:1
#: src/exercises/day-2/solutions-afternoon.md:97
msgid "Strings and Iterators"
msgstr "문자열과 반복자"
#: src/SUMMARY.md:126
msgid "Day 3: Morning"
msgstr "3일차 오전"
#: src/SUMMARY.md:131 src/generics.md:1
msgid "Generics"
msgstr "제네릭"
#: src/SUMMARY.md:132 src/generics/data-types.md:1
msgid "Generic Data Types"
msgstr "제네릭 데이터 타입"
#: src/SUMMARY.md:133 src/generics/methods.md:1
msgid "Generic Methods"
msgstr "제네릭 메서드"
#: src/SUMMARY.md:134 src/generics/monomorphization.md:1
msgid "Monomorphization"
msgstr "단형화"
#: src/SUMMARY.md:135 src/traits.md:1
msgid "Traits"
msgstr "트레잇(Trait)"
#: src/SUMMARY.md:136 src/traits/trait-objects.md:1
msgid "Trait Objects"
msgstr "트레잇 객체"
#: src/SUMMARY.md:137 src/traits/deriving-traits.md:1
msgid "Deriving Traits"
msgstr "트레잇 상속하기"
#: src/SUMMARY.md:138 src/traits/default-methods.md:1
msgid "Default Methods"
msgstr "기본 메서드"
#: src/SUMMARY.md:139 src/traits/trait-bounds.md:1
msgid "Trait Bounds"
msgstr "제네릭 타입 제한(트레잇 경계)"
#: src/SUMMARY.md:140
msgid "impl Trait"
msgstr "트레잇 구현하기"
#: src/SUMMARY.md:141 src/traits/important-traits.md:1
msgid "Important Traits"
msgstr "중요한 트레잇"
#: src/SUMMARY.md:142
msgid "Iterator"
msgstr "Iterator"
#: src/SUMMARY.md:143 src/traits/from-iterator.md:1
msgid "FromIterator"
msgstr "FromIterator"
#: src/SUMMARY.md:144
msgid "From and Into"
msgstr "From과 Into"
#: src/SUMMARY.md:145
msgid "Read and Write"
msgstr "Read와 Write"
#: src/SUMMARY.md:146
msgid "Drop"
msgstr "Drop"
#: src/SUMMARY.md:147
msgid "Default"
msgstr "Default"
#: src/SUMMARY.md:148
msgid "Operators: Add, Mul, ..."
msgstr "연산자: Add, Mul, ..."
#: src/SUMMARY.md:149
msgid "Closures: Fn, FnMut, FnOnce"
msgstr "클로저: Fn, FnMut, FnOnce"
#: src/SUMMARY.md:151 src/exercises/day-3/simple-gui.md:1
#: src/exercises/day-3/solutions-morning.md:3
msgid "A Simple GUI Library"
msgstr "간단한 GUI 라이브러리"
#: src/SUMMARY.md:153
msgid "Day 3: Afternoon"
msgstr "3일차 오후"
#: src/SUMMARY.md:155 src/error-handling.md:1
msgid "Error Handling"
msgstr "오류처리"
#: src/SUMMARY.md:156 src/error-handling/panics.md:1
msgid "Panics"
msgstr "패닉"
#: src/SUMMARY.md:157
msgid "Catching Stack Unwinding"
msgstr "스택 되감기"
#: src/SUMMARY.md:158
msgid "Structured Error Handling"
msgstr "구조화된 오류처리"
#: src/SUMMARY.md:159
msgid "Propagating Errors with ?"
msgstr "'?'를 이용한 오류 전파"
#: src/SUMMARY.md:160 src/error-handling/converting-error-types.md:1
#: src/error-handling/converting-error-types-example.md:1
msgid "Converting Error Types"
msgstr "오류타입 변환"
#: src/SUMMARY.md:162 src/error-handling/deriving-error-enums.md:1
msgid "Deriving Error Enums"
msgstr "또다른 오류 열거형"
#: src/SUMMARY.md:163 src/error-handling/dynamic-errors.md:1
msgid "Dynamic Error Types"
msgstr "동적인 에러 타입"
#: src/SUMMARY.md:164 src/error-handling/error-contexts.md:1
msgid "Adding Context to Errors"
msgstr "오류에 상황정보 추가"
#: src/SUMMARY.md:165 src/testing.md:1
msgid "Testing"
msgstr "테스트"
#: src/SUMMARY.md:166 src/testing/unit-tests.md:1
msgid "Unit Tests"
msgstr "단위 테스트"
#: src/SUMMARY.md:167 src/testing/test-modules.md:1
msgid "Test Modules"
msgstr "테스트 모듈"
#: src/SUMMARY.md:168 src/testing/doc-tests.md:1
msgid "Documentation Tests"
msgstr "문서화주석 테스트"
#: src/SUMMARY.md:169 src/testing/integration-tests.md:1
msgid "Integration Tests"
msgstr "통합 테스트"
#: src/SUMMARY.md:170 src/bare-metal/useful-crates.md:1
msgid "Useful crates"
msgstr "유용한 크레이트"
#: src/SUMMARY.md:171 src/unsafe.md:1
msgid "Unsafe Rust"
msgstr "안전하지 않은 러스트"
#: src/SUMMARY.md:172 src/unsafe/raw-pointers.md:1
msgid "Dereferencing Raw Pointers"
msgstr "원시 포인터 역참조(따라가기)"
#: src/SUMMARY.md:173 src/unsafe/mutable-static-variables.md:1
msgid "Mutable Static Variables"
msgstr "정적 가변 변수"
#: src/SUMMARY.md:174 src/unsafe/unions.md:1
msgid "Unions"
msgstr "Unions"
#: src/SUMMARY.md:175 src/unsafe/calling-unsafe-functions.md:1
msgid "Calling Unsafe Functions"
msgstr "안전하지 않은 함수 호출"
#: src/SUMMARY.md:176 src/unsafe/writing-unsafe-functions.md:1
msgid "Writing Unsafe Functions"
msgstr "안전하지 않은 함수 작성하기"
#: src/SUMMARY.md:177
msgid "Extern Functions"
msgstr "외부(다른언어) 함수들"
#: src/SUMMARY.md:178 src/unsafe/unsafe-traits.md:1
msgid "Implementing Unsafe Traits"
msgstr "안전하지 않은 트레잇 구현하기"
#: src/SUMMARY.md:180 src/exercises/day-3/safe-ffi-wrapper.md:1
#: src/exercises/day-3/solutions-afternoon.md:3
msgid "Safe FFI Wrapper"
msgstr "FFI래퍼"
#: src/SUMMARY.md:183 src/SUMMARY.md:253
#: src/running-the-course/course-structure.md:16 src/bare-metal/android.md:1
msgid "Android"
msgstr "안드로이드"
#: src/SUMMARY.md:188 src/android/setup.md:1
msgid "Setup"
msgstr "설치"
#: src/SUMMARY.md:189 src/android/build-rules.md:1
msgid "Build Rules"
msgstr "빌드 규칙"
#: src/SUMMARY.md:190
msgid "Binary"
msgstr "바이너리"
#: src/SUMMARY.md:191
msgid "Library"
msgstr "라이브러리"
#: src/SUMMARY.md:192 src/android/aidl.md:1
msgid "AIDL"
msgstr "AIDL"
#: src/SUMMARY.md:193
msgid "Interface"
msgstr "AIDL 인터페이스"
#: src/SUMMARY.md:194
msgid "Implementation"
msgstr "서비스 구현"
#: src/SUMMARY.md:195
msgid "Server"
msgstr "AIDL 서버"
#: src/SUMMARY.md:196 src/android/aidl/deploy.md:1
msgid "Deploy"
msgstr "배포"
#: src/SUMMARY.md:197
msgid "Client"
msgstr "클라이언트"
#: src/SUMMARY.md:198 src/android/aidl/changing.md:1
msgid "Changing API"
msgstr "API 수정"
#: src/SUMMARY.md:199 src/SUMMARY.md:243 src/android/logging.md:1
#: src/bare-metal/aps/logging.md:1
msgid "Logging"
msgstr "로깅"
#: src/SUMMARY.md:200 src/android/interoperability.md:1
msgid "Interoperability"
msgstr "상호운용성"
#: src/SUMMARY.md:201
msgid "With C"
msgstr "C와의 상호운용성"
#: src/SUMMARY.md:202
msgid "Calling C with Bindgen"
msgstr "Bindgen을 사용한 C호출"
#: src/SUMMARY.md:203
msgid "Calling Rust from C"
msgstr "C에서 러스트 호출"
#: src/SUMMARY.md:204 src/android/interoperability/cpp.md:1
msgid "With C++"
msgstr "C++와의 상호운용성"
#: src/SUMMARY.md:205
msgid "With Java"
msgstr "Java와의 상호운용성"
#: src/SUMMARY.md:209
msgid "Bare Metal: Morning"
msgstr "Bare Metal 오전"
#: src/SUMMARY.md:214
msgid "no_std"
msgstr "no_std"
#: src/SUMMARY.md:215
msgid "A Minimal Example"
msgstr "작은 예제"
#: src/SUMMARY.md:216
msgid "alloc"
msgstr "alloc"
#: src/SUMMARY.md:217 src/bare-metal/microcontrollers.md:1
msgid "Microcontrollers"
msgstr "마이크로컨트롤러"
#: src/SUMMARY.md:218 src/bare-metal/microcontrollers/mmio.md:1
msgid "Raw MMIO"
msgstr "원시 MMIO"
#: src/SUMMARY.md:219
msgid "PACs"
msgstr "PAC"
#: src/SUMMARY.md:220
msgid "HAL Crates"
msgstr "HAL 크레이트"
#: src/SUMMARY.md:221
msgid "Board Support Crates"
msgstr "보드 지원 크레이트"
#: src/SUMMARY.md:222
msgid "The Type State Pattern"
msgstr "Type State 패턴"
#: src/SUMMARY.md:223
msgid "embedded-hal"
msgstr "embedded-hal"
#: src/SUMMARY.md:224
msgid "probe-rs, cargo-embed"
msgstr "progo-rs, cargo-embed"
#: src/SUMMARY.md:225 src/bare-metal/microcontrollers/debugging.md:1
msgid "Debugging"
msgstr "디버깅"
#: src/SUMMARY.md:226 src/SUMMARY.md:246
msgid "Other Projects"
msgstr "다른 프로젝트"
#: src/SUMMARY.md:228 src/exercises/bare-metal/compass.md:1
#: src/exercises/bare-metal/solutions-morning.md:3
msgid "Compass"
msgstr "나침반"
#: src/SUMMARY.md:230
msgid "Bare Metal: Afternoon"
msgstr "Bare Metal 오후"
#: src/SUMMARY.md:232
msgid "Application Processors"
msgstr "애플리케이션 프로세서"
#: src/SUMMARY.md:233 src/bare-metal/aps/entry-point.md:1
msgid "Getting Ready to Rust"
msgstr "Rust 수행 준비"
#: src/SUMMARY.md:234
msgid "Inline Assembly"
msgstr "인라인 어셈블리"
#: src/SUMMARY.md:235
msgid "MMIO"
msgstr "MMIO"
#: src/SUMMARY.md:236
msgid "Let's Write a UART Driver"
msgstr "UART 드라이버 작성"
#: src/SUMMARY.md:237
msgid "More Traits"
msgstr "더 많은 트레잇"
#: src/SUMMARY.md:238
msgid "A Better UART Driver"
msgstr "더 나은 UART 드라이버"
#: src/SUMMARY.md:239 src/bare-metal/aps/better-uart/bitflags.md:1
msgid "Bitflags"
msgstr "비트플래그"
#: src/SUMMARY.md:240
msgid "Multiple Registers"
msgstr "더 많은 레지스터"
#: src/SUMMARY.md:241 src/bare-metal/aps/better-uart/driver.md:1
msgid "Driver"
msgstr "드라이버"
#: src/SUMMARY.md:242 src/SUMMARY.md:244
msgid "Using It"
msgstr "사용해 보기"
#: src/SUMMARY.md:245 src/bare-metal/aps/exceptions.md:1
msgid "Exceptions"
msgstr "예외"
#: src/SUMMARY.md:247
msgid "Useful Crates"
msgstr "유용한 크레이트"
#: src/SUMMARY.md:248
msgid "zerocopy"
msgstr "zerocopy"
#: src/SUMMARY.md:249
msgid "aarch64-paging"
msgstr "aarch64-paging"
#: src/SUMMARY.md:250
msgid "buddy_system_allocator"
msgstr "buddy_system_allocator"
#: src/SUMMARY.md:251
msgid "tinyvec"
msgstr "tinyvec"
#: src/SUMMARY.md:252
msgid "spin"
msgstr "회전"
#: src/SUMMARY.md:254 src/bare-metal/android/vmbase.md:1
msgid "vmbase"
msgstr "vmbase"
#: src/SUMMARY.md:256
msgid "RTC Driver"
msgstr "RTC 드라이버"
#: src/SUMMARY.md:259
msgid "Concurrency: Morning"
msgstr "동시성 오전"
#: src/SUMMARY.md:264 src/concurrency/threads.md:1
msgid "Threads"
msgstr "스레드"
#: src/SUMMARY.md:265 src/concurrency/scoped-threads.md:1
msgid "Scoped Threads"
msgstr "범위 스레드(Scoped Threads)"
#: src/SUMMARY.md:266 src/concurrency/channels.md:1
msgid "Channels"
msgstr "채널"
#: src/SUMMARY.md:267 src/concurrency/channels/unbounded.md:1
msgid "Unbounded Channels"
msgstr "무경계 채널"
#: src/SUMMARY.md:268 src/concurrency/channels/bounded.md:1
msgid "Bounded Channels"
msgstr "경계 채널"
#: src/SUMMARY.md:269
msgid "Send and Sync"
msgstr "Send와 Sync"
#: src/SUMMARY.md:269
msgid "Send"
msgstr "Send"
#: src/SUMMARY.md:269
msgid "Sync"
msgstr "Sync"
#: src/SUMMARY.md:272 src/concurrency/send-sync/examples.md:1
msgid "Examples"
msgstr "예제"
#: src/SUMMARY.md:273 src/concurrency/shared_state.md:1
msgid "Shared State"
msgstr "상태 공유"
#: src/SUMMARY.md:274
msgid "Arc"
msgstr "Arc"
#: src/SUMMARY.md:275
msgid "Mutex"
msgstr "Mutex"
#: src/SUMMARY.md:278 src/SUMMARY.md:299
#: src/exercises/concurrency/dining-philosophers.md:1
#: src/exercises/concurrency/solutions-morning.md:3
msgid "Dining Philosophers"
msgstr "식사하는 철학자들"
#: src/SUMMARY.md:279 src/exercises/concurrency/link-checker.md:1
msgid "Multi-threaded Link Checker"
msgstr "멀티스레드 링크 검사기"
#: src/SUMMARY.md:281
msgid "Concurrency: Afternoon"
msgstr "동시성 오후"
#: src/SUMMARY.md:283
msgid "Async Basics"
msgstr "비동기 관련 기본사항"
#: src/SUMMARY.md:284
msgid "async/await"
msgstr "async/await"
#: src/SUMMARY.md:285 src/async/futures.md:1
msgid "Futures"
msgstr "Future"
#: src/SUMMARY.md:286 src/async/runtimes.md:1
msgid "Runtimes"
msgstr "비동기 런타임들"
#: src/SUMMARY.md:287 src/async/runtimes/tokio.md:1
msgid "Tokio"
msgstr "Tokio"
#: src/SUMMARY.md:288 src/exercises/concurrency/link-checker.md:126
#: src/exercises/concurrency/chat-app.md:140 src/async/tasks.md:1
msgid "Tasks"
msgstr "태스크"
#: src/SUMMARY.md:289 src/async/channels.md:1
msgid "Async Channels"
msgstr "비동기 채널"
#: src/SUMMARY.md:291 src/async/control-flow/join.md:1
msgid "Join"
msgstr "Join"
#: src/SUMMARY.md:292 src/async/control-flow/select.md:1
msgid "Select"
msgstr "Select"
#: src/SUMMARY.md:293
msgid "Pitfalls"
msgstr "함정"
#: src/SUMMARY.md:294
msgid "Blocking the Executor"
msgstr "Executor 블로킹 하기"
#: src/SUMMARY.md:295 src/async/pitfalls/pin.md:1
msgid "Pin"
msgstr "Pin"
#: src/SUMMARY.md:296 src/async/pitfalls/async-traits.md:1
msgid "Async Traits"
msgstr "비동기 트레잇"
#: src/SUMMARY.md:297 src/async/pitfalls/cancellation.md:1
msgid "Cancellation"
msgstr "취소"
#: src/SUMMARY.md:300 src/exercises/concurrency/chat-app.md:1
#: src/exercises/concurrency/solutions-afternoon.md:119
msgid "Broadcast Chat Application"
msgstr "채팅 애플리케이션"
#: src/SUMMARY.md:303
msgid "Final Words"
msgstr "끝으로..."
#: src/SUMMARY.md:307 src/thanks.md:1
msgid "Thanks!"
msgstr "감사인사"
#: src/SUMMARY.md:308
msgid "Other Resources"
msgstr "러스트 참고 자료"
#: src/SUMMARY.md:309 src/credits.md:1
msgid "Credits"
msgstr "도와주신 분들"
#: src/SUMMARY.md:312 src/exercises/solutions.md:1
msgid "Solutions"
msgstr "해답"
#: src/SUMMARY.md:317
msgid "Day 1 Morning"
msgstr "1일차 오전"
#: src/SUMMARY.md:318
msgid "Day 1 Afternoon"
msgstr "1일차 오후"
#: src/SUMMARY.md:319
msgid "Day 2 Morning"
msgstr "2일차 오전"
#: src/SUMMARY.md:320
msgid "Day 2 Afternoon"
msgstr "2일차 오후"
#: src/SUMMARY.md:321
msgid "Day 3 Morning"
msgstr "3일차 오전"
#: src/SUMMARY.md:322
msgid "Day 3 Afternoon"
msgstr "3일차 오후"
#: src/SUMMARY.md:323
msgid "Bare Metal Rust Morning"
msgstr "Bare Metal 오전"
#: src/SUMMARY.md:324 src/exercises/bare-metal/solutions-afternoon.md:1
msgid "Bare Metal Rust Afternoon"
msgstr "전Bare Metal 오후"
#: src/SUMMARY.md:325
msgid "Concurrency Morning"
msgstr "동시성 오전"
#: src/SUMMARY.md:326
msgid "Concurrency Afternoon"
msgstr "동시성 오후"
#: src/index.md:3
msgid ""
"[![Build workflow](https://img.shields.io/github/actions/workflow/status/"
"google/comprehensive-rust/build.yml?style=flat-square)](https://github.com/"
"google/comprehensive-rust/actions/workflows/build.yml?query=branch%3Amain)"
msgstr ""
"[![Build workflow](https://img.shields.io/github/actions/workflow/status/"
"google/comprehensive-rust/build.yml?style=flat-square)](https://github.com/"
"google/comprehensive-rust/actions/workflows/build.yml?query=branch%3Amain)"
#: src/index.md:3
msgid "Build workflow"
msgstr "빌드 워크플로"
#: src/index.md:3
msgid ""
"[![Build workflow](https://img.shields.io/github/actions/workflow/status/"
"google/comprehensive-rust/build.yml?style=flat-square)](https://github.com/"
"google/comprehensive-rust/actions/workflows/build.yml?query=branch%3Amain) [!"
"[GitHub contributors](https://img.shields.io/github/contributors/google/"
"comprehensive-rust?style=flat-square)](https://github.com/google/"
"comprehensive-rust/graphs/contributors)"
msgstr ""
"[![Build workflow](https://img.shields.io/github/actions/workflow/status/"
"google/comprehensive-rust/build.yml?style=flat-square)](https://github.com/"
"google/comprehensive-rust/actions/workflows/build.yml?query=branch%3Amain) [!"
"[GitHub contributors](https://img.shields.io/github/contributors/google/"
"comprehensive-rust?style=flat-square)](https://github.com/google/"
"comprehensive-rust/graphs/contributors)"
#: src/index.md:4
msgid "GitHub contributors"
msgstr "GitHub 참여자"
#: src/index.md:4
msgid ""
"[![GitHub contributors](https://img.shields.io/github/contributors/google/"
"comprehensive-rust?style=flat-square)](https://github.com/google/"
"comprehensive-rust/graphs/contributors) [![GitHub stars](https://img.shields."
"io/github/stars/google/comprehensive-rust?style=flat-square)](https://github."
"com/google/comprehensive-rust/stargazers)"
msgstr ""
"[![GitHub contributors](https://img.shields.io/github/contributors/google/"
"comprehensive-rust?style=flat-square)](https://github.com/google/"
"comprehensive-rust/graphs/contributors) [![GitHub stars](https://img.shields."
"io/github/stars/google/comprehensive-rust?style=flat-square)](https://github."
"com/google/comprehensive-rust/stargazers)"
#: src/index.md:5
msgid "GitHub stars"
msgstr "GitHub stars"
#: src/index.md:5
msgid ""
"[![GitHub stars](https://img.shields.io/github/stars/google/comprehensive-"
"rust?style=flat-square)](https://github.com/google/comprehensive-rust/"
"stargazers)"
msgstr ""
"[![GitHub stars](https://img.shields.io/github/stars/google/comprehensive-"
"rust?style=flat-square)](https://github.com/google/comprehensive-rust/"
"stargazers)"
#: src/index.md:7
msgid ""
"This is a free Rust course developed by the Android team at Google. The "
"course covers the full spectrum of Rust, from basic syntax to advanced "
"topics like generics and error handling."
msgstr ""
"이 강의는 무료이며, Google의 Android 팀이 만들었습니다. 기본 문법부터 제네"
"릭, 에러 핸들링과 같은 고급주제까지 러스트의 모든 것을 포함합니다."
#: src/index.md:11
msgid ""
"The goal of the course is to teach you Rust. We assume you don't know "
"anything about Rust and hope to:"
msgstr ""
"강의는 당신이 러스트에 대해서 아무것도 모른다고 가정하고 아래의 목표를 가지"
"고 있습니다:"
#: src/index.md:14
msgid "Give you a comprehensive understanding of the Rust syntax and language."
msgstr "러스트 구문과 언어에 대한 포괄적인 이해를 제공합니다."
#: src/index.md:15
msgid "Enable you to modify existing programs and write new programs in Rust."
msgstr "기존 프로그램을 수정하고 러스트에서 새 프로그램을 작성할 수 있습니다."
#: src/index.md:16
msgid "Show you common Rust idioms."
msgstr "일반적인 러스트 관용구를 보여줍니다."
#: src/index.md:18
msgid "We call the first three course days Rust Fundamentals."
msgstr "강의의 첫 3일 동안에는 Rust의 기초를 다집니다."
#: src/index.md:20
msgid ""
"Building on this, you're invited to dive into one or more specialized topics:"
msgstr "그 후에는, 아래와 같은 개별 주제를 심화해서 공부할 수 있습니다:"
#: src/index.md:22
msgid ""
"[Android](android.md): a half-day course on using Rust for Android platform "
"development (AOSP). This includes interoperability with C, C++, and Java."
msgstr ""
"[Android](android.md): Android 플랫폼 개발(AOSP) 시 Rust 사용에 관한 반나절 "
"과정입니다. 여기에는 C, C++, Java와의 상호 운용성이 포함됩니다."
#: src/index.md:24
msgid ""
"[Bare-metal](bare-metal.md): a whole-day class on using Rust for bare-metal "
"(embedded) development. Both microcontrollers and application processors are "
"covered."
msgstr ""
"[Bare-metal](bare-metal.md): bare-metal(임베디드) 개발 시 Rust 사용에 관한 종"
"일 과정입니다. 마이크로컨트롤러와 애플리케이션 프로세서를 모두 다룹니다."
#: src/index.md:27
msgid ""
"[Concurrency](concurrency.md): a whole-day class on concurrency in Rust. We "
"cover both classical concurrency (preemptively scheduling using threads and "
"mutexes) and async/await concurrency (cooperative multitasking using "
"futures)."
msgstr ""
"[동시성](concurrency.md): Rust의 동시성에 관한 종일 과정입니다. 여기서는 고전"
"적인 동시성(스레드와 뮤텍스를 사용하여 선점형 스케줄링을 하는 것)과 async/"
"await 동시성(future를 사용하는 협력적인 멀티태스킹)을 모두 다룹니다."
#: src/index.md:33
msgid "Non-Goals"
msgstr "제외사항"
#: src/index.md:35
msgid ""
"Rust is a large language and we won't be able to cover all of it in a few "
"days. Some non-goals of this course are:"
msgstr ""
"러스트는 며칠만에 모든 것을 다루기에는 너무 큰 언어입니다. 그래서 아래와 같은"
"것을 목표로 하지 않습니다:"
#: src/index.md:38
msgid ""
"Learning how to develop macros: please see [Chapter 19.5 in the Rust Book]"
"(https://doc.rust-lang.org/book/ch19-06-macros.html) and [Rust by Example]"
"(https://doc.rust-lang.org/rust-by-example/macros.html) instead."
msgstr ""
"매크로 만들기: 매크로와 관련한 자세한 내용은 [러스트 프로그래밍 언어, 19.1절]"
"(https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html)과 [Rustonomicon]"
"(https://doc.rust-lang.org/nomicon/)를 참조하세요."
#: src/index.md:42
msgid "Assumptions"
msgstr "독자 수준에 대한 가정"
#: src/index.md:44
msgid ""
"The course assumes that you already know how to program. Rust is a "
"statically-typed language and we will sometimes make comparisons with C and "
"C++ to better explain or contrast the Rust approach."
msgstr ""
"본 강의는 여러분이 프로그래밍 자체에 대해서는 알고 있다고 가정합니다. 러스트"
"는 정적타입 언어이며, 강좌에서는 C/C++ 와의 비교, 대조를 통해 러스트를 설명"
"할 것입니다."
#: src/index.md:48
msgid ""
"If you know how to program in a dynamically-typed language such as Python or "
"JavaScript, then you will be able to follow along just fine too."
msgstr ""
"C/C++을 모르더라도 동적 타입 언어(Python이나 JavaScript 등) 프로그래밍 경험"
"이 있다면 따라오는데 큰 문제는 없을 것입니다."
#: src/index.md:53
msgid ""
"This is an example of a _speaker note_. We will use these to add additional "
"information to the slides. This could be key points which the instructor "
"should cover as well as answers to typical questions which come up in class."
msgstr ""
"이것은 \"발표자 노트\"의 예제입니다. 이 부분을 이용해서 추가 정보를 제공합니"
"다. 주로 강의실에서 제기되는 일반적인 질문에 대한 답변과 강사가 다루어야 할 "
"키 포인트일 수 있습니다."
#: src/running-the-course.md:3 src/running-the-course/course-structure.md:3
msgid "This page is for the course instructor."
msgstr "강사를 위한 안내 페이지입니다."
#: src/running-the-course.md:5
msgid ""
"Here is a bit of background information about how we've been running the "
"course internally at Google."
msgstr ""
"다음은 구글 내부에서 이 과정을 어떤식으로 운영해왔는지에 대한 배경 정보입니"
"다."
#: src/running-the-course.md:8
msgid "Before you run the course, you will want to:"
msgstr "강의를 실행하기 위한 준비:"
#: src/running-the-course.md:10
msgid ""
"Make yourself familiar with the course material. We've included speaker "
"notes to help highlight the key points (please help us by contributing more "
"speaker notes!). When presenting, you should make sure to open the speaker "
"notes in a popup (click the link with a little arrow next to \"Speaker "
"Notes\"). This way you have a clean screen to present to the class."
msgstr ""
"강의 자료를 숙지합니다. 주요 요점을 강조하기 위해 강의 참조 노트를 포함하였습"
"니다. (추가적인 노트를 작성하여 제공해 주시면 감사하겠습니다.) 강의 참조 노트"
"의 링크를 누르면 별도의 팝업으로 분리가 되며, 메인 화면에서는 사라집니다. 깔"
"끔한 화면으로 강의를 진행할 수 있습니다."
#: src/running-the-course.md:16
msgid ""
"Decide on the dates. Since the course takes at least three full days, we "
"recommend that you schedule the days over two weeks. Course participants "
"have said that they find it helpful to have a gap in the course since it "
"helps them process all the information we give them."
msgstr ""
"강의 날짜를 정합니다. 최소 3일에 걸쳐서 진행이 되기 때문에, 두 주에 걸쳐서 스"
"케줄을 잡는 것을 권합니다. 기존 강의 수강생들의 피드백에 따르면, 연달아서 강"
"의를 진행하는 것 보다, 강의를 띄엄띄엄 하는 것이 강의 내용을 소화하는데 더 도"
"움이 되었다고 합니다."
#: src/running-the-course.md:21
msgid ""
"Find a room large enough for your in-person participants. We recommend a "
"class size of 15-25 people. That's small enough that people are comfortable "
"asking questions --- it's also small enough that one instructor will have "
"time to answer the questions. Make sure the room has _desks_ for yourself "
"and for the students: you will all need to be able to sit and work with your "
"laptops. In particular, you will be doing a lot of live-coding as an "
"instructor, so a lectern won't be very helpful for you."
msgstr ""
"충분한 공간을 확보합니다. 15에서 20명 규모의 공간을 추천합니다. 수강생과 강사"
"가 질의를 하기에 충분한 시간과 공간이어야 합니다. 강사나 수강생 모두 \\_책상_"
"을 사용할 수 있는 강의실이면 좋습니다. 강의 중에 강사가 라이브 코딩을 하게 "
"될 경우가 많으며, 이때 자리에 앉아 노트북을 사용하는 것이 도움이 됩니다."
#: src/running-the-course.md:29
msgid ""
"On the day of your course, show up to the room a little early to set things "
"up. We recommend presenting directly using `mdbook serve` running on your "
"laptop (see the [installation instructions](https://github.com/google/"
"comprehensive-rust#building)). This ensures optimal performance with no lag "
"as you change pages. Using your laptop will also allow you to fix typos as "
"you or the course participants spot them."
msgstr ""
"강의 당일 조금 일찍 와서 준비합니다. 강사 노트북에서 `mdbook serve`를 이용해 "
"직접 프레젠테이션 하면 페이지 이동 시의 지연이 없습니다.([설치 방법](https://"
"github.com/google/comprehensive-rust#building)을 참조하세요.) 또한, 그렇게 하"
"면 강의 도중 오타를 발견했을 때 그 자리에서 바로 수정 가능하다는 장점도 있습"
"니다."
#: src/running-the-course.md:35
msgid ""
"Let people solve the exercises by themselves or in small groups. We "
"typically spend 30-45 minutes on exercises in the morning and in the "
"afternoon (including time to review the solutions). Make sure to ask people "
"if they're stuck or if there is anything you can help with. When you see "
"that several people have the same problem, call it out to the class and "
"offer a solution, e.g., by showing people where to find the relevant "
"information in the standard library."
msgstr ""
"수강생들이 직접 (개별 혹은 그룹으로) 연습문제를 풀도록 합니다. 대체로 오전, "
"오후에 각각 30-45분 정도를 연습문제에 할당합니다 (이는 해답을 보고 설명하는 "
"시간까지 포함합니다). 막혀 도움을 필요로 하는 수강생이 없는지 수시로 확인합니"
"다. 만약 같은 문제를 여러 사람이 겪고 있다면, 그 문제를 강의실 전체 인원에게 "
"알리고 해결책을 제시합니다. 예를 들어 표준 라이브러리 어디에 가면 그 문제에 "
"대한 해답을 찾을 수 있는지 알려 줍니다."
#: src/running-the-course.md:43
msgid ""
"That is all, good luck running the course! We hope it will be as much fun "
"for you as it has been for us!"
msgstr ""
"이제 준비는 끝났습니다. 우리가 그랬듯이 여러분들도 이 강의를 즐기시길 바랍니"
"다!"
#: src/running-the-course.md:46
msgid ""
"Please [provide feedback](https://github.com/google/comprehensive-rust/"
"discussions/86) afterwards so that we can keep improving the course. We "
"would love to hear what worked well for you and what can be made better. "
"Your students are also very welcome to [send us feedback](https://github.com/"
"google/comprehensive-rust/discussions/100)!"
msgstr ""
"강의를 계속 개선할 수 있도록 [피드백](https://github.com/google/"
"comprehensive-rust/discussions/86)을 제공해 주십시오. 우리는 무엇이 좋았고, "
"무엇이 모자랐는지 듣고 싶습니다. 수강생들로 부터의 [피드백](https://github."
"com/google/comprehensive-rust/discussions/100)도 환영합니다!"
#: src/running-the-course/course-structure.md:5
msgid "The course is fast paced and covers a lot of ground:"
msgstr "강의는 빠른 속도로 진행되며, 아래 내용들을 다룹니다:"
#: src/running-the-course/course-structure.md:7
msgid "Day 1: Basic Rust, ownership and the borrow checker."
msgstr "1일차: 러스트 기본, 소유권(ownership)과 빌림(borrow) 체크."
#: src/running-the-course/course-structure.md:8
msgid "Day 2: Compound data types, pattern matching, the standard library."
msgstr "2일차: 복합 데이터 유형, 패턴 매칭, 표준 라이브러리."
#: src/running-the-course/course-structure.md:9
msgid "Day 3: Traits and generics, error handling, testing, unsafe Rust."
msgstr ""
"3일차: 트레잇(trait)와 제네릭(generic), 오류 처리, 테스트, 안전하지 않은 러스"
"트."
#: src/running-the-course/course-structure.md:11
msgid "Deep Dives"
msgstr "심화 학습"
#: src/running-the-course/course-structure.md:13
msgid ""
"In addition to the 3-day class on Rust Fundamentals, we cover some more "
"specialized topics:"
msgstr "Rust 기초에 관한 3일 과정 이후에는, 다음과 같은 전문 주제를 다룹니다:"
#: src/running-the-course/course-structure.md:18
msgid ""
"The [Android Deep Dive](../android.md) is a half-day course on using Rust "
"for Android platform development. This includes interoperability with C, C+"
"+, and Java."
msgstr ""
"[Android 심화 학습](../android.md)는 Android 플랫폼 개발 시 Rust 사용에 관한 "
"반나절 과정입니다. 여기에는 C, C++, Java와의 상호 운용성이 포함됩니다."
#: src/running-the-course/course-structure.md:22
msgid ""
"You will need an [AOSP checkout](https://source.android.com/docs/setup/"
"download/downloading). Make a checkout of the [course repository](https://"
"github.com/google/comprehensive-rust) on the same machine and move the `src/"
"android/` directory into the root of your AOSP checkout. This will ensure "
"that the Android build system sees the `Android.bp` files in `src/android/`."
msgstr ""
"[AOSP 코드](https://source.android.com/docs/setup/download/downloading)를 여"
"러분의 컴퓨터에 체크아웃해야 합니다. 그런 다음, 그 컴퓨터에서 [과정 저장소]"
"(https://github.com/google/comprehensive-rust)를 체크아웃하고 `src/android/` "
"디렉터리를 AOSP 코드의 루트로 이동합니다. 이렇게 하면 안드로이드 빌드 시스템"
"에서 과제용으로 추가된 `Android.bp`파일을 인식할 수 있습니다."
#: src/running-the-course/course-structure.md:27
msgid ""
"Ensure that `adb sync` works with your emulator or real device and pre-build "
"all Android examples using `src/android/build_all.sh`. Read the script to "
"see the commands it runs and make sure they work when you run them by hand."
msgstr ""
"`adb sync` 명렁어가 에뮬레이터 혹은 실제 장치와 작동하는지 확인합니다. 그리"
"고 `src/android/build_all.sh`를 수행해서 모든 안드로이드 예제를 미리 빌드해 "
"보세요. 그 쉘 스크립트를 읽고, 그 안에서 수행되는 명령어들을 확인한 후 각 명"
"령어들을 수동으로 실행해도 잘 되는지 확인하세요."
#: src/running-the-course/course-structure.md:34
msgid "Bare-Metal"
msgstr "Bare-Metal"
#: src/running-the-course/course-structure.md:36
msgid ""
"The [Bare-Metal Deep Dive](../bare-metal.md): a full day class on using Rust "
"for bare-metal (embedded) development. Both microcontrollers and application "
"processors are covered."
msgstr ""
"[Bare-Metal 심화 학습](../bare-metal.md): bare-metal(임베디드) 개발 시 Rust "
"사용에 관한 종일 과정입니다. 마이크로컨트롤러와 애플리케이션 프로세서를 모두 "
"다룹니다."
#: src/running-the-course/course-structure.md:40
msgid ""
"For the microcontroller part, you will need to buy the [BBC micro:bit]"
"(https://microbit.org/) v2 development board ahead of time. Everybody will "
"need to install a number of packages as described on the [welcome page](../"
"bare-metal.md)."
msgstr ""
"마이크로컨트롤러 파트를 진행하기 위해서는 [BBC micro:bit](https://microbit."
"org/) v2 개발 보드를 미리 구매해야 합니다. 모든 사용자는 [시작 페이지](../"
"bare-metal.md)에 설명된 대로 각종 패키지를 설치해야 합니다."
#: src/running-the-course/course-structure.md:45
msgid "Concurrency"
msgstr "동시성"
#: src/running-the-course/course-structure.md:47
msgid ""
"The [Concurrency Deep Dive](../concurrency.md) is a full day class on "
"classical as well as `async`/`await` concurrency."
msgstr ""
"[동시성 심화학습](../concurrency.md)은 고전적인 동시성 및 `async`/`await` 동"
"시성을 다루는 종일 과정입니다."
#: src/running-the-course/course-structure.md:50
msgid ""
"You will need a fresh crate set up and the dependencies downloaded and ready "
"to go. You can then copy/paste the examples into `src/main.rs` to experiment "
"with them:"
msgstr ""
"새 크레이트를 설정하고 몇 가지 의존성을 다운로드해 두어야 합니다. 그런 다음 "
"예제를 `src/main.rs`에 복사/붙여넣기 하여 테스트 해 볼 수 있습니다:"
#: src/running-the-course/course-structure.md:54
msgid ""
"```shell\n"
"cargo init concurrency\n"
"cd concurrency\n"
"cargo add tokio --features full\n"
"cargo run\n"
"```"
msgstr ""
"```shell\n"
"cargo init concurrency\n"
"cd concurrency\n"
"cargo add tokio --features full\n"
"cargo run\n"
"```"
#: src/running-the-course/course-structure.md:61
msgid "Format"
msgstr "강의 형식"
#: src/running-the-course/course-structure.md:63
msgid ""
"The course is meant to be very interactive and we recommend letting the "
"questions drive the exploration of Rust!"
msgstr ""
"이 강의는 강사와 수강생이 양방향으로 소통하면서 진행하도록 디자인 되었습니"
"다. 다양한 질문을 통해 러스트의 여러 부분을 탐험할 수 있도록 하세요!"
#: src/running-the-course/keyboard-shortcuts.md:3
msgid "There are several useful keyboard shortcuts in mdBook:"
msgstr "다음은, mdBook 시스템(현 사이트)에서 유용한 단축키들 입니다:"
#: src/running-the-course/keyboard-shortcuts.md:5
msgid "Arrow-Left"
msgstr "왼쪽 화살표"
#: src/running-the-course/keyboard-shortcuts.md:5
msgid ": Navigate to the previous page."
msgstr ": 이전 페이지로 이동합니다."
#: src/running-the-course/keyboard-shortcuts.md:6
msgid "Arrow-Right"
msgstr "오른쪽 화살표"
#: src/running-the-course/keyboard-shortcuts.md:6
msgid ": Navigate to the next page."
msgstr ": 다음 페이지로 이동합니다."
#: src/running-the-course/keyboard-shortcuts.md:7 src/cargo/code-samples.md:19
msgid "Ctrl + Enter"
msgstr "Ctrl + Enter"
#: src/running-the-course/keyboard-shortcuts.md:7
msgid ": Execute the code sample that has focus."
msgstr ": 현재 포커스를 받은 코드 샘플 블록을 실행합니다."
#: src/running-the-course/keyboard-shortcuts.md:8
msgid "s"
msgstr "s"
#: src/running-the-course/keyboard-shortcuts.md:8
msgid ": Activate the search bar."
msgstr ""
": 검색창을 활성화합니다.(mdBook 문제로 23.01.19 기준 영어로만 가능합니다.)"
#: src/running-the-course/translations.md:3
msgid ""
"The course has been translated into other languages by a set of wonderful "
"volunteers:"
msgstr ""
"이 과정은 다른 언어로도 제공됩니다. 괄호 안은 번역에 도움 주신 분들입니다:"
#: src/running-the-course/translations.md:6
msgid ""
"[Brazilian Portuguese](https://google.github.io/comprehensive-rust/pt-BR/) "
"by [@rastringer](https://github.com/rastringer), [@hugojacob](https://github."
"com/hugojacob), [@joaovicmendes](https://github.com/joaovicmendes) and "
"[@henrif75](https://github.com/henrif75)."
msgstr ""
"[브라질 포르투갈어](https://google.github.io/comprehensive-rust/pt-BR/): "
"[@rastringer](https://github.com/rastringer), [@hugojacob](https://github."
"com/hugojacob), [@joaovicmendes](https://github.com/joaovicmendes) 그리고 "
"[@henrif75](https://github.com/henrif75)가 제공."
#: src/running-the-course/translations.md:7
msgid ""
"[Korean](https://google.github.io/comprehensive-rust/ko/) by [@keispace]"
"(https://github.com/keispace), [@jiyongp](https://github.com/jiyongp) and "
"[@jooyunghan](https://github.com/jooyunghan)."
msgstr ""
"[한국어](https://google.github.io/comprehensive-rust/ko/): [@keispace]"
"(https://github.com/keispace), [@jiyongp](https://github.com/jiyongp) 그리고 "
"[@jooyunghan](https://github.com/jooyunghan)가 제공."
#: src/running-the-course/translations.md:9
msgid ""
"Use the language picker in the top-right corner to switch between languages."
msgstr "페이지 오른쪽 위의 메뉴를 통해 다른 언어로 전환할 수 있습니다."
#: src/running-the-course/translations.md:11
msgid "Incomplete Translations"
msgstr "번역 문제"
#: src/running-the-course/translations.md:13
msgid ""
"There is a large number of in-progress translations. We link to the most "
"recently updated translations:"
msgstr ""
"진행 중인 번역이 많습니다. 최근에 업데이트된 번역본으로 연결되는 링크는 다음"
"과 같습니다:"
#: src/running-the-course/translations.md:16
msgid ""
"[Bengali](https://google.github.io/comprehensive-rust/bn/) by [@raselmandol]"
"(https://github.com/raselmandol)."
msgstr ""
"[벵갈어](https://google.github.io/comprehensive-rust/bn/): [@raselmandol]"
"(https://github.com/raselmandol) 제공."
#: src/running-the-course/translations.md:17
msgid ""
"[French](https://google.github.io/comprehensive-rust/fr/) by [@KookaS]"
"(https://github.com/KookaS) and [@vcaen](https://github.com/vcaen)."
msgstr ""
"[프랑스어](https://google.github.io/comprehensive-rust/fr/): [@KookaS]"
"(https://github.com/KookaS) 및 [@vcaen](https://github.com/vcaen) 제공."
#: src/running-the-course/translations.md:18
msgid ""
"[German](https://google.github.io/comprehensive-rust/de/) by [@Throvn]"
"(https://github.com/Throvn) and [@ronaldfw](https://github.com/ronaldfw)."
msgstr ""
"[독일어](https://google.github.io/comprehensive-rust/de/): [@Throvn](https://"
"github.com/Throvn) 및 [@ronaldfw](https://github.com/ronaldfw) 제공."
#: src/running-the-course/translations.md:19
msgid ""
"[Japanese](https://google.github.io/comprehensive-rust/ja/) by [@CoinEZ-JPN]"
"(https://github.com/CoinEZ) and [@momotaro1105](https://github.com/"
"momotaro1105)."
msgstr ""
"[일본어](https://google.github.io/comprehensive-rust/ja/): [@CoinEZ-JPN]"
"(https://github.com/CoinEZ) 및 [@momotaro1105](https://github.com/"
"momotaro1105) 제공."
#: src/running-the-course/translations.md:21
msgid ""
"If you want to help with this effort, please see [our instructions](https://"
"github.com/google/comprehensive-rust/blob/main/TRANSLATIONS.md) for how to "
"get going. Translations are coordinated on the [issue tracker](https://"
"github.com/google/comprehensive-rust/issues/282)."
msgstr ""
"이 과정의 번역 작업에 도움을 주고 싶다면 [여기](https://github.com/google/"
"comprehensive-rust/blob/main/TRANSLATIONS.md) 설명된 내용을 참고하세요. 진행 "
"중인 번역 작업에 대한 내용은 [이슈 트래커](https://github.com/google/"
"comprehensive-rust/issues/282)를 참고하세요."
#: src/cargo.md:3
msgid ""
"When you start reading about Rust, you will soon meet [Cargo](https://doc."
"rust-lang.org/cargo/), the standard tool used in the Rust ecosystem to build "
"and run Rust applications. Here we want to give a brief overview of what "
"Cargo is and how it fits into the wider ecosystem and how it fits into this "
"training."
msgstr ""
"러스트를 시작하려고하면 당신은 곧 [Cargo](https://doc.rust-lang.org/cargo/)라"
"는, 러스트 생태계에서 사용하는 표준 빌드/실행 도구를 만날 것 입니다. 여기서"
"는 카고가 무엇인지, 그리고 카고가 러스트 생태계에서 어떤 역할을 하는지, 그리"
"고 이 강의에서 어떻게 사용될 지에 대해 간략히 설명하겠습니다."
#: src/cargo.md:8
msgid "Installation"
msgstr "설치하기"
#: src/cargo.md:10
msgid "**Please follow the instructions on <https://rustup.rs/>.**"
msgstr "**<https://rustup.rs/>의 설치 방법을 따르세요.**"
#: src/cargo.md:12
msgid ""
"This will give you the Cargo build tool (`cargo`) and the Rust compiler "
"(`rustc`). You will also get `rustup`, a command line utility that you can "
"use to install/switch toolchains, setup cross compilation, etc."
msgstr ""
"위 설치 방법을 따르면, 빌드 시스템인 카고(`cargo`)와 러스트 컴파일러(`rustc`)"
"가 설치됩니다. 이와 함께, `rustup`도 설치되는데 이 툴은 툴체인을 설치하고, 다"
"른 툴체인으로 전환하고, 크로스 컴파일 설정을 하는 일을 담당하는 커맨드 라인 "
"유틸리티 입니다."
#: src/cargo.md:16
msgid ""
"On Debian/Ubuntu, you can also install Cargo, the Rust source and the [Rust "
"formatter](https://github.com/rust-lang/rustfmt) via `apt`. However, this "
"gets you an outdated rust version and may lead to unexpected behavior. The "
"command would be:"
msgstr ""
"데비안/우분투 시스템에서는 `apt`를 이용해서 카고, 러스트 소스, [러스트 포매"
"터](https://github.com/rust-lang/rustfmt)를 설치할 수 있습니다. 그러나 이 방"
"법을 따를 경우 최신 버전이 아닌 러스트를 사용게되며, 그 결과 예상치 못한 문제"
"를 겪을 수도 있습니다. 설치 명령어는 아래와 같습니다:"
#: src/cargo.md:18
msgid ""
"```shell\n"
" sudo apt install cargo rust-src rustfmt\n"
"```"
msgstr ""
"```shell\n"
"$ sudo apt install cargo rust-src rustfmt\n"
"```"
#: src/cargo.md:22
msgid ""
"We suggest using [VS Code](https://code.visualstudio.com/) to edit the code "
"(but any LSP compatible editor works with rust-analyzer[3](https://rust-"
"analyzer.github.io/))."
msgstr ""
"우리는 코드 에디터로 [VS Code](https://code.visualstudio.com/)를 추천합니다. "
"그러나 LSP를 지원하는 (그래서 rust-analyzer[3](https://rust-analyzer.github."
"io/)와 연동이 가능한) 에디터라면 어떤 것이라도 괜찮습니다."
#: src/cargo.md:24
msgid ""
"Some folks also like to use the [JetBrains](https://www.jetbrains.com/"
"clion/) family of IDEs, which do their own analysis but have their own "
"tradeoffs. If you prefer them, you can install the [Rust Plugin](https://www."
"jetbrains.com/rust/). Please take note that as of January 2023 debugging "
"only works on the CLion version of the JetBrains IDEA suite."
msgstr ""
"어떤 사람들은 [JetBrains](https://www.jetbrains.com/clion/) 제품군을 선호하기"
"도 합니다. 이 제품들은 rust-analyzer 를 활용하지 않고 IDE 자체적으로 구문분석"
"을 합니다. 만약 이 IDE를 설치하셨다면 [Rust Plugin](https://www.jetbrains."
"com/rust/)를 설치하시기 바랍니다. 다만 2023년 1월 기준, 디버깅은 JetBrains "
"IDEA suite의 CLion 버전에서만 작동한다는 점에 유의하시기 바랍니다."
#: src/cargo/rust-ecosystem.md:1
msgid "The Rust Ecosystem"
msgstr "러스트 생태계"
#: src/cargo/rust-ecosystem.md:3
msgid ""
"The Rust ecosystem consists of a number of tools, of which the main ones are:"
msgstr ""
"러스트의 생태계는 여러가지 도구들로 구성되어 있으며, 그 중 중요한 것들은 아래"
"와 같습니다:"
#: src/cargo/rust-ecosystem.md:5
msgid ""
"`rustc`: the Rust compiler which turns `.rs` files into binaries and other "
"intermediate formats."
msgstr ""
"`rustc`: `.rs` 확장자 파일을 바이너리 혹은 다른 중간 형식으로 변환해주는 "
"Rust 컴파일러입니다."
#: src/cargo/rust-ecosystem.md:8
msgid ""
"`cargo`: the Rust dependency manager and build tool. Cargo knows how to "
"download dependencies, usually hosted on <https://crates.io>, and it will "
"pass them to `rustc` when building your project. Cargo also comes with a "
"built-in test runner which is used to execute unit tests."
msgstr ""
"`cargo`: 러스트 의존성 관리자이자 빌드 시스템 입니다. 여러분의 프로젝트에 명"
"시된 의존성들을 <https://crates.io>에서 자동으로 다운로드 받고, 그 소스코드"
"를 `rustc`로 전달하여 빌드를 시킵니다. 또한 유닛 테스트를 실행하는 테스트 러"
"너를 내장하고 있습니다."
#: src/cargo/rust-ecosystem.md:13
msgid ""
"`rustup`: the Rust toolchain installer and updater. This tool is used to "
"install and update `rustc` and `cargo` when new versions of Rust is "
"released. In addition, `rustup` can also download documentation for the "
"standard library. You can have multiple versions of Rust installed at once "
"and `rustup` will let you switch between them as needed."
msgstr ""
"`rustup`: 러스트 툴체인 설치 프로그램이자 업데이트 프로그램 입니다. 이 도구"
"는 새 버전의 러스트가 출시될 때 `rustc` 및 `cargo` 설치하고 업데이트하는 데 "
"사용됩니다. 또한 `rustup`은 표준 라이브러리에 대한 문서를 다운로드할 수도 있"
"습니다. 한 번에 여러 버전의 러스트를 설치할 수 있으며 `rustup`을 이용해서 실"
"제로 사용할 버전을 변경할 수 있습니다."
#: src/cargo/rust-ecosystem.md:21 src/hello-world.md:25
#: src/hello-world/small-example.md:27 src/why-rust/runtime.md:10
#: src/why-rust/modern.md:21 src/basic-syntax/compound-types.md:30
#: src/basic-syntax/references.md:23
#: src/pattern-matching/destructuring-enums.md:35
#: src/error-handling/try-operator.md:48
#: src/error-handling/converting-error-types-example.md:50
#: src/concurrency/threads.md:30 src/async/async-await.md:25
msgid "Key points:"
msgstr "키 포인트:"
#: src/cargo/rust-ecosystem.md:23
msgid ""
"Rust has a rapid release schedule with a new release coming out every six "
"weeks. New releases maintain backwards compatibility with old releases --- "
"plus they enable new functionality."
msgstr ""
"러스트는 6주마다 새로운 릴리즈가 발표되며 이전 릴리즈와의 호환성을 유지하고 "
"있습니다."
#: src/cargo/rust-ecosystem.md:27
msgid ""
"There are three release channels: \"stable\", \"beta\", and \"nightly\"."
msgstr ""
"릴리즈는 3가지 버전으로 제공됩니다: \"stable\", \"beta\" 그리고 \"nightly\"."
#: src/cargo/rust-ecosystem.md:29
msgid ""
"New features are being tested on \"nightly\", \"beta\" is what becomes "
"\"stable\" every six weeks."
msgstr ""
"새로운 기능은 \"nightly\" -> \"beta\" -(6주 후)-> \"stable\" 로 변경됩니다."
#: src/cargo/rust-ecosystem.md:32
msgid ""
"Dependencies can also be resolved from alternative [registries](https://doc."
"rust-lang.org/cargo/reference/registries.html), git, folders, and more."
msgstr ""
"의존성은 다양한 [저장소](registries), git 프로젝트, 디렉터리 등에서 제공될 "
"수 있습니다."
#: src/cargo/rust-ecosystem.md:34
msgid ""
"Rust also has [editions](https://doc.rust-lang.org/edition-guide/): the "
"current edition is Rust 2021. Previous editions were Rust 2015 and Rust 2018."
msgstr ""
"러스트는 [에디션](https://doc.rust-lang.org/edition-guide/)으로 구분됩니다. "
"현재는 Rust 2021 에디션입니다. 이 전 에디션으로 Rust 2015와 Rust 2018이 있습"
"니다."
#: src/cargo/rust-ecosystem.md:37
msgid ""
"The editions are allowed to make backwards incompatible changes to the "
"language."
msgstr "에디션은 이전 에디션과 호환이 되지 않을 수 있습니다."
#: src/cargo/rust-ecosystem.md:40
msgid ""
"To prevent breaking code, editions are opt-in: you select the edition for "
"your crate via the `Cargo.toml` file."
msgstr ""
"에디션이 바뀌면서 프로그램이 의도치 않게 깨지는 문제를 막기 위해, 각 프로그램"
"은 자신이 빌드될 에디션을 명시적으로 `Cargo.toml`에 지정해야 합니다."
#: src/cargo/rust-ecosystem.md:43
msgid ""
"To avoid splitting the ecosystem, Rust compilers can mix code written for "
"different editions."
msgstr ""
"러스트 생태계가 에디션 별로 파편회 되는 것을 막기 위해, 러스트 컴파일러는 서"
"로 다른 에디션에서 작성된 코드들을 하나의 바이너리로 묶을 수 있습니다."
#: src/cargo/rust-ecosystem.md:46
msgid ""
"Mention that it is quite rare to ever use the compiler directly not through "
"`cargo` (most users never do)."
msgstr ""
"`cargo`를 사용하지 않고 컴파일러를 직접 사용하는 경우는 거의 없음을 언급해 주"
"시기 바랍니다."
#: src/cargo/rust-ecosystem.md:48
msgid ""
"It might be worth alluding that Cargo itself is an extremely powerful and "
"comprehensive tool. It is capable of many advanced features including but "
"not limited to: "
msgstr ""
"카고 자체가 매우 강력하고 포괄적인 도구임을 적극적으로 알리세요. 카고는 다음"
"과 같은 다양한 고급 기능을 제공합니다: "
#: src/cargo/rust-ecosystem.md:49
msgid "Project/package structure"
msgstr "프로젝트/패키지 구조화"
#: src/cargo/rust-ecosystem.md:50
msgid "[workspaces](https://doc.rust-lang.org/cargo/reference/workspaces.html)"
msgstr ""
"[워크스페이스](https://doc.rust-lang.org/cargo/reference/workspaces.html)"
#: src/cargo/rust-ecosystem.md:51
msgid "Dev Dependencies and Runtime Dependency management/caching"
msgstr "개발/런타임 종속성 관리 및 캐싱"
#: src/cargo/rust-ecosystem.md:52
msgid ""
"[build scripting](https://doc.rust-lang.org/cargo/reference/build-scripts."
"html)"
msgstr ""
"[빌드 스크립트](https://doc.rust-lang.org/cargo/reference/build-scripts.html)"
#: src/cargo/rust-ecosystem.md:53
msgid ""
"[global installation](https://doc.rust-lang.org/cargo/commands/cargo-install."
"html)"
msgstr ""
"[전역 설치](https://doc.rust-lang.org/cargo/commands/cargo-install.html)"
#: src/cargo/rust-ecosystem.md:54
msgid ""
"It is also extensible with sub command plugins as well (such as [cargo "
"clippy](https://github.com/rust-lang/rust-clippy))."
msgstr ""
"[cargo clippy](https://github.com/rust-lang/rust-clippy)와 같은 하위 플러그인"
"으로 확장 가능."
#: src/cargo/rust-ecosystem.md:55
msgid ""
"Read more from the [official Cargo Book](https://doc.rust-lang.org/cargo/)"
msgstr ""
"[공식 Cargo Book](https://doc.rust-lang.org/cargo/)에서 자세한 사항을 확인하"
"시기 바랍니다."
#: src/cargo/code-samples.md:1
msgid "Code Samples in This Training"
msgstr "강의에서의 코드 샘플"
#: src/cargo/code-samples.md:3
msgid ""
"For this training, we will mostly explore the Rust language through examples "
"which can be executed through your browser. This makes the setup much easier "
"and ensures a consistent experience for everyone."
msgstr ""
"이 강의자료에 있는 모든 예제는 브라우저에서 바로 수행 가능합니다. 이렇게 한 "
"이유는, 준비 과정을 단순화 시키고, 모두가 같은 환경에서 작업할 수 있도록 하"
"기 위함입니다."
#: src/cargo/code-samples.md:7
msgid ""
"Installing Cargo is still encouraged: it will make it easier for you to do "
"the exercises. On the last day, we will do a larger exercise which shows you "
"how to work with dependencies and for that you need Cargo."
msgstr ""
"그럼에도 불구하고, 카고(cargo)를 직접 설치하는 것을 강력 권장합니다. 이게 과"
"제 작성에 더 도움이 될겁니다. 또한, 마지막 날에는 의존성이 있는 예제를 작업하"
"게 될 텐데, 그 때에는 어차피 카고가 필요합니다."
#: src/cargo/code-samples.md:11
msgid "The code blocks in this course are fully interactive:"
msgstr "이 강의 자료의 코드 블록들은 전부 인터엑티브 합니다:"
#: src/cargo/code-samples.md:13
msgid ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"Edit me!\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"Edit me!\");\n"
"}\n"
"```"
#: src/cargo/code-samples.md:19
msgid "You can use "
msgstr "코드 블록에 포커스를 두고 "
#: src/cargo/code-samples.md:19
msgid " to execute the code when focus is in the text box."
msgstr " 를 눌러 실행해 볼 수 있습니다."
#: src/cargo/code-samples.md:24
msgid ""
"Most code samples are editable like shown above. A few code samples are not "
"editable for various reasons:"
msgstr ""
"강의에서 대부분의 코드 샘플은 위와 같이 수정할수 있지만 일부 코드는 다음과 같"
"은 이유로 수정할 수 없습니다:"
#: src/cargo/code-samples.md:27
msgid ""
"The embedded playgrounds cannot execute unit tests. Copy-paste the code and "
"open it in the real Playground to demonstrate unit tests."
msgstr ""
"유닛 테스트는 내장 플레이그라운드에서 실행이 안됩니다. 외부 플레이그라운드 사"
"이트에 붙여넣어 테스트를 실행하시기 바랍니다."
#: src/cargo/code-samples.md:30
msgid ""
"The embedded playgrounds lose their state the moment you navigate away from "
"the page! This is the reason that the students should solve the exercises "
"using a local Rust installation or via the Playground."
msgstr ""
"내장된 플레이그라운드에서는 페이지 이동시 작성된 모든 내용이 사라집니다. 따라"
"서 로컬 환경이나 외부 플레이그라운드 사이트에서 연습문제를 해결하는 것이 좋습"
"니다."
#: src/cargo/running-locally.md:1
msgid "Running Code Locally with Cargo"
msgstr "로컬 환경의 카고"
#: src/cargo/running-locally.md:3
msgid ""
"If you want to experiment with the code on your own system, then you will "
"need to first install Rust. Do this by following the [instructions in the "
"Rust Book](https://doc.rust-lang.org/book/ch01-01-installation.html). This "
"should give you a working `rustc` and `cargo`. At the time of writing, the "
"latest stable Rust release has these version numbers:"
msgstr ""
"만약 개인용 컴퓨터에서 코드를 실행해보려면 먼저 러스트를 설치해야 합니다. "
"[Rust Book](https://doc.rust-lang.org/book/ch01-01-installation.html)의 지침"
"에 따라 `rustc`와 `cargo`를 함께 설치 하시기 바랍니다. 설치 후 아래 커맨드를 "
"통해 각 툴의 버전을 확인 할 수 있습니다:"
#: src/cargo/running-locally.md:8
msgid ""
"```shell\n"
"% rustc --version\n"
"rustc 1.69.0 (84c898d65 2023-04-16)\n"
"% cargo --version\n"
"cargo 1.69.0 (6e9a83356 2023-04-12)\n"
"```"
msgstr ""
"```shell\n"
"% rustc --version\n"
"rustc 1.69.0 (84c898d65 2023-04-16)\n"
"% cargo --version\n"
"cargo 1.69.0 (6e9a83356 2023-04-12)\n"
"```"
#: src/cargo/running-locally.md:15
msgid ""
"You can use any later version too since Rust maintains backwards "
"compatibility."
msgstr ""
"이 버전보다 더 최신의 버전이어도 상관 없습니다. 러스트는 하위 호환성을 지원합"
"니다."
#: src/cargo/running-locally.md:17
msgid ""
"With this in place, follow these steps to build a Rust binary from one of "
"the examples in this training:"
msgstr ""
"정상적으로 설치가 되었으면, 강의 예제중 하나를 러스트 바이너리로 빌드해 봅시"
"다:"
#: src/cargo/running-locally.md:20
msgid "Click the \"Copy to clipboard\" button on the example you want to copy."
msgstr "예시 블록에 있는 \"Copy to clipboard\" 버튼을 클릭해서 복사합니다."
#: src/cargo/running-locally.md:22
msgid ""
"Use `cargo new exercise` to create a new `exercise/` directory for your code:"
msgstr ""
"터미널에서 `cargo new exercise`를 입력해서 새로운 `exercise/` 폴더를 만듭니"
"다:"
#: src/cargo/running-locally.md:24
msgid ""
"```shell\n"
"$ cargo new exercise\n"
" Created binary (application) `exercise` package\n"
"```"
msgstr ""
"```shell\n"
"$ cargo new exercise\n"
" Created binary (application) `exercise` package\n"
"```"
#: src/cargo/running-locally.md:29
msgid ""
"Navigate into `exercise/` and use `cargo run` to build and run your binary:"
msgstr "`exercise/` 폴더로 이동한 후, `cargo run` 커맨드로 코드를 실행합니다:"
#: src/cargo/running-locally.md:31
msgid ""
"```shell\n"
"$ cd exercise\n"
"$ cargo run\n"
" Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise)\n"
" Finished dev [unoptimized + debuginfo] target(s) in 0.75s\n"
" Running `target/debug/exercise`\n"
"Hello, world!\n"
"```"
msgstr ""
"```shell\n"
"$ cd exercise\n"
"$ cargo run\n"
" Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise)\n"
" Finished dev [unoptimized + debuginfo] target(s) in 0.75s\n"
" Running `target/debug/exercise`\n"
"Hello, world!\n"
"```"
#: src/cargo/running-locally.md:40
msgid ""
"Replace the boiler-plate code in `src/main.rs` with your own code. For "
"example, using the example on the previous page, make `src/main.rs` look like"
msgstr ""
"`src/main.rs`에 코드를 작성합니다. 예를 들어 이전 페이지의 소스를 아래와 같"
"이 `src/main.rs`에 작성합니다"
#: src/cargo/running-locally.md:43
msgid ""
"```rust\n"
"fn main() {\n"
" println!(\"Edit me!\");\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"fn main() {\n"
" println!(\"Edit me!\");\n"
"}\n"
"```"
#: src/cargo/running-locally.md:49
msgid "Use `cargo run` to build and run your updated binary:"
msgstr "`cargo run`커맨드로 소스를 빌드하고 실행합니다:"
#: src/cargo/running-locally.md:51
msgid ""
"```shell\n"
"$ cargo run\n"
" Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise)\n"
" Finished dev [unoptimized + debuginfo] target(s) in 0.24s\n"
" Running `target/debug/exercise`\n"
"Edit me!\n"
"```"
msgstr ""
"```shell\n"
"$ cargo run\n"
" Compiling exercise v0.1.0 (/home/mgeisler/tmp/exercise)\n"
" Finished dev [unoptimized + debuginfo] target(s) in 0.24s\n"
" Running `target/debug/exercise`\n"
"Edit me!\n"
"```"
#: src/cargo/running-locally.md:59
msgid ""
"Use `cargo check` to quickly check your project for errors, use `cargo "
"build` to compile it without running it. You will find the output in `target/"
"debug/` for a normal debug build. Use `cargo build --release` to produce an "
"optimized release build in `target/release/`."
msgstr ""
"`cargo check`커맨드는 빠르게 에러를 확인할 수 있습니다. `cargo build`는 실행"
"없이 컴파일만 합니다. 이 경우에 `target/debug/`폴더에서 output을 확인 할 수 "
"있습니다. `cargo build --release`커맨드는 릴리즈 버전용 최적화를 켜서 컴파일"
"하며 `target/release/`폴더에서 확인 할 수 있습니다."
#: src/cargo/running-locally.md:64
msgid ""
"You can add dependencies for your project by editing `Cargo.toml`. When you "
"run `cargo` commands, it will automatically download and compile missing "
"dependencies for you."
msgstr ""
"`Cargo.toml`파일에는 의존성 패키지를 추가할 수 있습니다. `cargo`커맨드를 실행"
"하면 자동으로 의존성 패키지를 다운로드하고 컴파일 까지 해 줍니다."
#: src/cargo/running-locally.md:72
msgid ""
"Try to encourage the class participants to install Cargo and use a local "
"editor. It will make their life easier since they will have a normal "
"development environment."
msgstr ""
"수강생들이 카고를 설치하고 로컬 편집기를 이용하도록 독려하세요. 조금 귀찮을 "
"수도 있지만, 이렇게 해야만 좀 더 실제와 가까운 개발환경을 갖추게 되는 것입니"
"다."
#: src/welcome-day-1.md:1
msgid "Welcome to Day 1"
msgstr "1일차 개요"
#: src/welcome-day-1.md:3
msgid ""
"This is the first day of Rust Fundamentals. We will cover a lot of ground "
"today:"
msgstr "강의 첫 날입니다. 오늘 배울 것이 참 많습니다:"
#: src/welcome-day-1.md:6
msgid ""
"Basic Rust syntax: variables, scalar and compound types, enums, structs, "
"references, functions, and methods."
msgstr ""
"러스트 기본 문법: 변수, 스칼라 / 복합 타입, 열거형, 구조체, 참조형, 함수와 메"
"서드."
#: src/welcome-day-1.md:9
msgid ""
"Memory management: stack vs heap, manual memory management, scope-based "
"memory management, and garbage collection."
msgstr ""
"메모리 관리: 스택과 힙, 수동 메모리 관리, 스코프(범위)기반 메모리 관리, 가비"
"지 컬렉션(GC)"
#: src/welcome-day-1.md:12
msgid ""
"Ownership: move semantics, copying and cloning, borrowing, and lifetimes."
msgstr "소유권: Move 문법, 복사와 복제, 빌림, 수명."
#: src/welcome-day-1.md:16
msgid "Please remind the students that:"
msgstr "학생들에게 다음을 상기시켜 주시기 바랍니다:"
#: src/welcome-day-1.md:18
msgid ""
"They should ask questions when they get them, don't save them to the end."
msgstr "궁금한 점이 있으면 주저하지 말고 질문 해야 합니다."
#: src/welcome-day-1.md:19
msgid ""
"The class is meant to be interactive and discussions are very much "
"encouraged!"
msgstr "이 수업은 상호작용이 요합니다. 토론을 망설이지 마세요!"
#: src/welcome-day-1.md:20
msgid ""
"As an instructor, you should try to keep the discussions relevant, i.e., "
"keep the discussions related to how Rust does things vs some other "
"language. It can be hard to find the right balance, but err on the side of "
"allowing discussions since they engage people much more than one-way "
"communication."
msgstr ""
"강사로서 토론이 옆길로 새지 않게 주의하세요. 예를 들어 러스트와 다른 언어들"
"을 비교한다든지 하는 것은 좋습니다. 적절한 균형을 찾기 애매한 경우라면 토론"
"을 허용하는 쪽이 일방적인 강의보다는 더 많은 사람들의 참여를 이끌어 낼 수 있"
"습니다."
#: src/welcome-day-1.md:24
msgid ""
"The questions will likely mean that we talk about things ahead of the slides."
msgstr "질문이 슬라이드보다 앞서가도 괜찮습니다."
#: src/welcome-day-1.md:25
msgid ""
"This is perfectly okay! Repetition is an important part of learning. "
"Remember that the slides are just a support and you are free to skip them as "
"you like."
msgstr ""
"학습에 있어서 반복은 매우 중요합니다. 슬라이드는 그저 도움을 줄 뿐, 원하는 대"
"로 건너띄어도 됩니다."
#: src/welcome-day-1.md:29
msgid ""
"The idea for the first day is to show _just enough_ of Rust to be able to "
"speak about the famous borrow checker. The way Rust handles memory is a "
"major feature and we should show students this right away."
msgstr ""
"첫 날 강의의 목표는, 러스트에서 그 유명한 빌림 확인에 대해서 이야기 할 수 있"
"을 정도 까지만 러스트를 소개하는 것입니다. 러스트의 가장 독특한 특징이 메모리"
"를 다루는 방식이기 때문에, 학생들에게 이 부분 을 우선적으로 보여주려 합니다."
#: src/welcome-day-1.md:33
msgid ""
"If you're teaching this in a classroom, this is a good place to go over the "
"schedule. We suggest splitting the day into two parts (following the slides):"
msgstr ""
"만약 당신이 강의실에서 가르치고 있다면, 이 슬라이드는 일정을 검토하기에 적합"
"한 곳입니다. 하루치 강의를 아래처럼 오전 오후로 나누어 진행하는 것을 추천합니"
"다. (슬라이드가 그런식으로 나뉘어 있습니다.)"
#: src/welcome-day-1.md:36
msgid "Morning: 9:00 to 12:00,"
msgstr "오전: 9:00 ~ 12:00,"
#: src/welcome-day-1.md:37
msgid "Afternoon: 13:00 to 16:00."
msgstr "오후: 13:00 ~ 16:00."
#: src/welcome-day-1.md:39
msgid ""
"You can of course adjust this as necessary. Please make sure to include "
"breaks, we recommend a break every hour!"
msgstr ""
"물론 필요에 따라 조절할 수 있습니다. 강의 중간에 쉬는시간을 넣는 것을 잊지 마"
"세요. 매 시간 휴식을 갖는걸 추천합니다!"
#: src/welcome-day-1/what-is-rust.md:3
msgid ""
"Rust is a new programming language which had its [1.0 release in 2015]"
"(https://blog.rust-lang.org/2015/05/15/Rust-1.0.html):"
msgstr ""
"러스트는 2015년에 [버전 1.0](https://blog.rust-lang.org/2015/05/15/Rust-1.0."
"html)을 릴리즈 한 새로운 프로그램 언어입니다:"
#: src/welcome-day-1/what-is-rust.md:5
msgid "Rust is a statically compiled language in a similar role as C++"
msgstr "러스트는 C++와 유사한 정적 컴파일 언어입니다"
#: src/welcome-day-1/what-is-rust.md:6
msgid "`rustc` uses LLVM as its backend."
msgstr "`rustc`는 LLVM을 백엔드로 사용합니다."
#: src/welcome-day-1/what-is-rust.md:7
msgid ""
"Rust supports many [platforms and architectures](https://doc.rust-lang.org/"
"nightly/rustc/platform-support.html):"
msgstr "러스트는 다양한 플랫폼과 아키텍쳐를 지원합니다:"
#: src/welcome-day-1/what-is-rust.md:9
msgid "x86, ARM, WebAssembly, ..."
msgstr "x86, ARM, WebAssembly, ..."
#: src/welcome-day-1/what-is-rust.md:10
msgid "Linux, Mac, Windows, ..."
msgstr "Linux, Mac, Windows, ..."
#: src/welcome-day-1/what-is-rust.md:11
msgid "Rust is used for a wide range of devices:"
msgstr "러스트는 다양한 장치에서 사용될 수 있습니다:"
#: src/welcome-day-1/what-is-rust.md:12
msgid "firmware and boot loaders,"
msgstr "펌웨어와 부트로더(임베디드)"
#: src/welcome-day-1/what-is-rust.md:13
msgid "smart displays,"
msgstr "스마트 디스플레이,"
#: src/welcome-day-1/what-is-rust.md:14
msgid "mobile phones,"
msgstr "스마트폰,"
#: src/welcome-day-1/what-is-rust.md:15
msgid "desktops,"
msgstr "데스크탑,"
#: src/welcome-day-1/what-is-rust.md:16
msgid "servers."
msgstr "서버."
#: src/welcome-day-1/what-is-rust.md:21
msgid "Rust fits in the same area as C++:"
msgstr "러스트는 C++가 사용되는 대부분의 곳에서 사용 가능합니다:"
#: src/welcome-day-1/what-is-rust.md:23
msgid "High flexibility."
msgstr "높은 유연성."
#: src/welcome-day-1/what-is-rust.md:24
msgid "High level of control."
msgstr "높은 수준의 제어."
#: src/welcome-day-1/what-is-rust.md:25
msgid ""
"Can be scaled down to very constrained devices such as microcontrollers."
msgstr "마이크로컨트롤러 같은 매우 제한된 장치로 스케일 다운 가능."
#: src/welcome-day-1/what-is-rust.md:26
msgid "Has no runtime or garbage collection."
msgstr "별도의 런타임을 필요로 하지 않으며, 가비지 컬렉션도 없음."
#: src/welcome-day-1/what-is-rust.md:27
msgid "Focuses on reliability and safety without sacrificing performance."
msgstr "성능을 타협하지 않으면서도 안정성과 안전에 중점을 둠."
#: src/hello-world.md:3
msgid ""
"Let us jump into the simplest possible Rust program, a classic Hello World "
"program:"
msgstr ""
"가장 간단한 러스트 프로그램으로써, 고전적인 Hello World 를 작성해 보겠습니다:"
#: src/hello-world.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"Hello 🌍!\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"Hello 🌍!\");\n"
"}\n"
"```"
#: src/hello-world.md:12
msgid "What you see:"
msgstr "확인할 수 있는 것들:"
#: src/hello-world.md:14
msgid "Functions are introduced with `fn`."
msgstr "함수는 `fn`으로 선언합니다."
#: src/hello-world.md:15
msgid "Blocks are delimited by curly braces like in C and C++."
msgstr "C/C++ 와 마찬가지로 중괄호`{}`로 블록을 표시합니다."
#: src/hello-world.md:16
msgid "The `main` function is the entry point of the program."
msgstr "`main` 함수는 프로그램 진입점입니다."
#: src/hello-world.md:17
msgid "Rust has hygienic macros, `println!` is an example of this."
msgstr ""
"러스트는 똑똑한 매크로(hygienic macros) 시스템을 가지고 있습니다. `println!`"
"는 그 예시입니다."
#: src/hello-world.md:18
msgid "Rust strings are UTF-8 encoded and can contain any Unicode character."
msgstr ""
"러스트의 문자열은 UTF-8로 인코딩되며 이모지와 같은 유니코드 문자를 포함할 수 "
"있습니다."
#: src/hello-world.md:22
msgid ""
"This slide tries to make the students comfortable with Rust code. They will "
"see a ton of it over the next three days so we start small with something "
"familiar."
msgstr ""
"이 슬라이드는 학생들이 러스트 코드에 익숙해지기 위해 작성되었습니다. 앞으로 3"
"일 동안 많은 코드를 접할 것이기 때문에 우선 친숙한 코드부터 시작합니다."
#: src/hello-world.md:27
msgid ""
"Rust is very much like other languages in the C/C++/Java tradition. It is "
"imperative and it doesn't try to reinvent things unless absolutely necessary."
msgstr ""
"러스트는 C/C++/Java와 같은 전통적인 다른 언어와 매우 유사합니다. 러스트는 절"
"차적 언어입니다. 정말로 필요한 경우가 아니라면, 러스트는 이미 존재하는 것을 "
"새로 구현하려고 하지 않습니다."
#: src/hello-world.md:31
msgid "Rust is modern with full support for things like Unicode."
msgstr "러스트는 유니코드 지원과 같은 현대 언어의 특징을 전부 지원합니다."
#: src/hello-world.md:33
msgid ""
"Rust uses macros for situations where you want to have a variable number of "
"arguments (no function [overloading](basic-syntax/functions-interlude.md))."
msgstr ""
"러스트는 인자의 개수를 사전에 지정할 수 없는 상황에서 함수 [오버로딩](basic-"
"syntax/functions-interlude.md)대신 매크로를 사용합니다."
#: src/hello-world.md:36
msgid ""
"Macros being 'hygienic' means they don't accidentally capture identifiers "
"from the scope they are used in. Rust macros are actually only [partially "
"hygienic](https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene."
"html)."
msgstr ""
"똑똑한 매크로(hygienic macro)는 매크로가 사용되는 스코프에서 의도치 않게 변수"
"를 가로채지 않습니다. 사실 러스트 매크로는 완전히 hygenic하지는 않습니다. [링"
"크](https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene.html)를 참"
"고하세요."
#: src/hello-world.md:40
msgid ""
"Rust is multi-paradigm. For example, it has powerful [object-oriented "
"programming features](https://doc.rust-lang.org/book/ch17-00-oop.html), and, "
"while it is not a functional language, it includes a range of [functional "
"concepts](https://doc.rust-lang.org/book/ch13-00-functional-features.html)."
msgstr ""
"러스트는 멀티 패러다임 언어입니다. 예를 들어 강력한 [객체 지향 프로그래밍 기"
"능](https://doc.rust-lang.org/book/ch17-00-oop.html)을 지원하기도 하며, 함수"
"형 언어로 분류되지는 않지만 폭넓은 범위의 [함수형 컨셉](https://doc.rust-"
"lang.org/book/ch13-00-functional-features.html)을 지원합니다."
#: src/hello-world/small-example.md:3
msgid "Here is a small example program in Rust:"
msgstr "러스트로 작성된 작은 예제입니다:"
#: src/hello-world/small-example.md:5
msgid ""
"```rust,editable\n"
"fn main() { // Program entry point\n"
" let mut x: i32 = 6; // Mutable variable binding\n"
" print!(\"{x}\"); // Macro for printing, like printf\n"
" while x != 1 { // No parenthesis around expression\n"
" if x % 2 == 0 { // Math like in other languages\n"
" x = x / 2;\n"
" } else {\n"
" x = 3 * x + 1;\n"
" }\n"
" print!(\" -> {x}\");\n"
" }\n"
" println!();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() { // 프로그램 진입점입니다.\n"
" let mut x: i32 = 6; // 가변 변수 할당(binding)입니다.\n"
" print!(\"{x}\"); // printf와 같은 출력을 위한 매크로 입니다.\n"
" while x != 1 { // 표현식에 괄호는 없습니다.\n"
" if x % 2 == 0 { // 다른 언어와 같은 수학연산식이 사용됩니다.\n"
" x = x / 2;\n"
" } else {\n"
" x = 3 * x + 1;\n"
" }\n"
" print!(\" -> {x}\");\n"
" }\n"
" println!();\n"
"}\n"
"```"
#: src/hello-world/small-example.md:23
msgid ""
"The code implements the Collatz conjecture: it is believed that the loop "
"will always end, but this is not yet proved. Edit the code and play with "
"different inputs."
msgstr ""
"이 코드는 콜라츠 추측(Collatz conjecture)으로 구현됩니다: 반복문이 언제나 종"
"료될 것이라고 믿지만 증명된 것은 아닙니다. 코드를 수정하고 실행해 보시기 바랍"
"니다."
#: src/hello-world/small-example.md:29
msgid ""
"Explain that all variables are statically typed. Try removing `i32` to "
"trigger type inference. Try with `i8` instead and trigger a runtime integer "
"overflow."
msgstr ""
"모든 변수가 컴파일 시 정해진 타입을 가짐을 설명합니다. `i32`를 삭제하여 컴파"
"일러가 타입 추론을 하도록 해 봅니다. `i32`을 `i8`로 변경하여 런타임 오버플로"
"를 유발해 볼 수 있습니다."
#: src/hello-world/small-example.md:32
msgid "Change `let mut x` to `let x`, discuss the compiler error."
msgstr "`let mut x`를 `let x`로 수정하여 컴파일 오류에 대해 토론합니다."
#: src/hello-world/small-example.md:34
msgid ""
"Show how `print!` gives a compilation error if the arguments don't match the "
"format string."
msgstr ""
"인자가 포맷 문자열과 일치하지 않는 경우 `print!`에서 컴파일 오류가 발생함을 "
"언급하는 것도 좋습니다."
#: src/hello-world/small-example.md:37
msgid ""
"Show how you need to use `{}` as a placeholder if you want to print an "
"expression which is more complex than just a single variable."
msgstr ""
"단일 변수보다 복잡한 식을 출려하려면 `{}`을 자리 표시자로 사용하는 방법을 보"
"여 줍니다."
#: src/hello-world/small-example.md:40
msgid ""
"Show the students the standard library, show them how to search for `std::"
"fmt` which has the rules of the formatting mini-language. It's important "
"that the students become familiar with searching in the standard library."
msgstr ""
"학생들에게 표준 라이브러리가 어디 있는지 알려 주고는, `print!`가 지원하는 포"
"맷팅 언어의 문법을 알기 위해 `std::fmt`를 검색해야 한다는 것을 가르치세요.학"
"생들이 표준 라이브러리의 검색 기능에 익숙해 지도록 하는 것이 중요합니다."
#: src/hello-world/small-example.md:44
msgid ""
"In a shell `rustup doc std::fmt` will open a browser on the local std::fmt "
"documentation"
msgstr ""
"쉘에서 `rustup doc std::fmt`를 수행하면 로컬 브라우저로 `std:fmt`에 대한 문"
"서를 보여줍니다"
#: src/why-rust.md:3
msgid "Some unique selling points of Rust:"
msgstr "러스트만의 독특한 세일즈 포인트(장점):"
#: src/why-rust.md:5
msgid "Compile time memory safety."
msgstr "컴파일 시 메모리 안전이 보장됨."
#: src/why-rust.md:6
msgid "Lack of undefined runtime behavior."
msgstr "정의되지 않은 런타임 동작이 없음."
#: src/why-rust.md:7
msgid "Modern language features."
msgstr "현대적인 언어 기능."
#: src/why-rust.md:11
msgid ""
"Make sure to ask the class which languages they have experience with. "
"Depending on the answer you can highlight different features of Rust:"
msgstr ""
"수강생들에게 어떤 프로그래밍 언어를 사용했는지 물어보시기 바랍니다. 어떤 언어"
"를 사용했느냐에 따라 러스트에서 어떤 점을 강조해야 할지를 고민해 보세요:"
#: src/why-rust.md:14
msgid ""
"Experience with C or C++: Rust eliminates a whole class of _runtime errors_ "
"via the borrow checker. You get performance like in C and C++, but you don't "
"have the memory unsafety issues. In addition, you get a modern language with "
"constructs like pattern matching and built-in dependency management."
msgstr ""
"C/C++: 러스트는 '빌림'검사기를 통해서 수행중에 발생할 수 있는 모든 에러를 제"
"거합니다. 러스트는 C와 C++과 비슷한 수준의 성능을 보여주면서도, 그 언어들에"
"서 종종 발생하는 메모리 관련 오류가 없습니다. 또한, 패턴 매칭이나, 기본적으"
"로 제공되는 종속성 관리와 같은 현대적인 언어의 기능들을 제공합니다."
#: src/why-rust.md:19
msgid ""
"Experience with Java, Go, Python, JavaScript...: You get the same memory "
"safety as in those languages, plus a similar high-level language feeling. In "
"addition you get fast and predictable performance like C and C++ (no garbage "
"collector) as well as access to low-level hardware (should you need it)"
msgstr ""
"Java, Go, Python, JavaScript: 이 언어들과 동일한 메모리 안정성과 함께, '하이"
"레벨'언어의 느낌을 느낄 수 있습니다. 거기에 더해, 가비지 컬렉터가 없는 C/C+"
"+와 유사한 수준의 빠르고 예측 가능한 성능을 기대할 수 있습니다. 그리고 필요"
"한 경우 저수준 하드웨어를 다루는 코드로 작성할 수 있습니다."
#: src/why-rust/compile-time.md:3
msgid "Static memory management at compile time:"
msgstr "컴파일 시 정적 메모리 관리:"
#: src/why-rust/compile-time.md:5
msgid "No uninitialized variables."
msgstr "초기화되지 않는 변수가 없습니다."
#: src/why-rust/compile-time.md:6
msgid "No memory leaks (_mostly_, see notes)."
msgstr "메모리 누출 없음(_거의_. 강의참조노트 참고.)"
#: src/why-rust/compile-time.md:7
msgid "No double-frees."
msgstr "메모리 이중 해제가 원천적으로 불가능 합니다."
#: src/why-rust/compile-time.md:8
msgid "No use-after-free."
msgstr "메모리 해제 후 사용이 원천적으로 불가능 합니다."
#: src/why-rust/compile-time.md:9
msgid "No `NULL` pointers."
msgstr "`NULL`포인터는 없습니다."
#: src/why-rust/compile-time.md:10
msgid "No forgotten locked mutexes."
msgstr "뮤텍스를 잠궈 놓고 여는 것을 잊는 실수를 할 수 없습니다."
#: src/why-rust/compile-time.md:11
msgid "No data races between threads."
msgstr "스레드간 데이터 레이스를 막아줍니다."
#: src/why-rust/compile-time.md:12
msgid "No iterator invalidation."
msgstr "반복자가 갑자기 무효화 되는 경우가 없습니다."
#: src/why-rust/compile-time.md:16
msgid ""
"It is possible to produce memory leaks in (safe) Rust. Some examples are:"
msgstr ""
"(안전한) 러스트에서도 메모리 누출이 발생할 수 있는 몇 가지 경우가 있습니다:"
#: src/why-rust/compile-time.md:19
msgid ""
"You can use [`Box::leak`](https://doc.rust-lang.org/std/boxed/struct.Box."
"html#method.leak) to leak a pointer. A use of this could be to get runtime-"
"initialized and runtime-sized static variables"
msgstr ""
"[`Box::leak`](https://doc.rust-lang.org/std/boxed/struct.Box.html#method."
"leak)을 이용하여 포인터를 의도적으로 누출시킬 수 있습니다. 이를 이용해서 런타"
"임이 생성하고 런타임이 크기를 정한 정적 변수를 가져올 수 있습니다"
#: src/why-rust/compile-time.md:21
msgid ""
"You can use [`std::mem::forget`](https://doc.rust-lang.org/std/mem/fn.forget."
"html) to make the compiler \"forget\" about a value (meaning the destructor "
"is never run)."
msgstr ""
"[`std::mem::forget`](https://doc.rust-lang.org/std/mem/fn.forget.html)을 사용"
"하여 컴파일러가 값에 대해 \"잊도록\" 만들 수 있습니다(소멸자가 실행되지 않음"
"을 의미합니다)."
#: src/why-rust/compile-time.md:23
msgid ""
"You can also accidentally create a [reference cycle](https://doc.rust-lang."
"org/book/ch15-06-reference-cycles.html) with `Rc` or `Arc`."
msgstr ""
"`Rc` 또는 `Arc`를 사용하여 실수로 [순환참조](https://doc.rust-lang.org/book/"
"ch15-06-reference-cycles.html)를 생성할 수도 있습니다."
#: src/why-rust/compile-time.md:25
msgid ""
"In fact, some will consider infinitely populating a collection a memory leak "
"and Rust does not protect from those."
msgstr ""
"컬렉션을 무한정 채우는 것을 메모리 누출로 간주할 수도 있지만, 러스트는 이를 "
"보호하진 못합니다."
#: src/why-rust/compile-time.md:28
msgid ""
"For the purpose of this course, \"No memory leaks\" should be understood as "
"\"Pretty much no _accidental_ memory leaks\"."
msgstr ""
"본 강의에서는 \"메모리 누출 없음\"을 \"우발적인 메모리 누출 없음\"으로 이해해"
"야 합니다."
#: src/why-rust/runtime.md:3
msgid "No undefined behavior at runtime:"
msgstr "런타임 시 정의되지 않음(undefined) 동작 없음:"
#: src/why-rust/runtime.md:5
msgid "Array access is bounds checked."
msgstr "배열 접근시 경계 체크."
#: src/why-rust/runtime.md:6
msgid "Integer overflow is defined (panic or wrap-around)."
msgstr "정수형 타입의 변수에서 오버플로우 발생시 동작이 잘 정의되어있습니다."
#: src/why-rust/runtime.md:12
msgid ""
"Integer overflow is defined via the [`overflow-checks`](https://doc.rust-"
"lang.org/rustc/codegen-options/index.html#overflow-checks) compile-time "
"flag. If enabled, the program will panic (a controlled crash of the "
"program), otherwise you get wrap-around semantics. By default, you get "
"panics in debug mode (`cargo build`) and wrap-around in release mode (`cargo "
"build --release`)."
msgstr ""
"정수형 오버플로우는 [`overflow-checks`](https://doc.rust-lang.org/rustc/"
"codegen-options/index.html#overflow-checks) 컴파일 타임 플래그를 통해 정의됩"
"니다. 이 플래그가 켜지면, 프로그램은 정수형 오버플로우 발생시 panic (프로그램"
"을 크래시 시키는 잘 정의된 방법) 합니다. 이 플래그가 꺼지면, 오버플로우는 "
"wrap-around 가 됩니다. 기본적으로 디버그 모드(`cargo build`)에서는 패닉이, 릴"
"리즈 모드(`cargo build --release`)에서는 wrap-around가 발생합니다."
#: src/why-rust/runtime.md:18
msgid ""
"Bounds checking cannot be disabled with a compiler flag. It can also not be "
"disabled directly with the `unsafe` keyword. However, `unsafe` allows you to "
"call functions such as `slice::get_unchecked` which does not do bounds "
"checking."
msgstr ""
"컴파일 플래그를 사용하여 경계체크를 무력화 할 수 없습니다. `unsafe`를 사용하"
"더라도 마찬가지입니다. 하지만 `unsafe`에서 호출 가능한 `slice::get_unchecked`"
"같은 함수는 경계 검사를 수행하지 않습니다."
#: src/why-rust/modern.md:3
msgid "Rust is built with all the experience gained in the last decades."
msgstr ""
"러스트는 지난 수십년간의 모든 (프로그래밍 언어들의) 경험으로 만들어졌습니다."
#: src/why-rust/modern.md:5
msgid "Language Features"
msgstr "언어적 특징"
#: src/why-rust/modern.md:7
msgid "Enums and pattern matching."
msgstr "열거형과 패턴 매칭."
#: src/why-rust/modern.md:8
msgid "Generics."
msgstr "제네릭."
#: src/why-rust/modern.md:9
msgid "No overhead FFI."
msgstr "FFI 런타임 오버헤드 없음."
#: src/why-rust/modern.md:10
msgid "Zero-cost abstractions."
msgstr "비용이 들지 않는 추상화."
#: src/why-rust/modern.md:12
msgid "Tooling"
msgstr "도구들"
#: src/why-rust/modern.md:14
msgid "Great compiler errors."
msgstr "친절한 컴파일러 오류메시지."
#: src/why-rust/modern.md:15
msgid "Built-in dependency manager."
msgstr "내장 종속성 관리자."
#: src/why-rust/modern.md:16
msgid "Built-in support for testing."
msgstr "내장 테스트 지원."
#: src/why-rust/modern.md:17
msgid "Excellent Language Server Protocol support."
msgstr "LSP (Language Server Protocol, 언어 서버 프로토콜) 지원이 잘되어 있음."
#: src/why-rust/modern.md:23
msgid ""
"Zero-cost abstractions, similar to C++, means that you don't have to 'pay' "
"for higher-level programming constructs with memory or CPU. For example, "
"writing a loop using `for` should result in roughly the same low level "
"instructions as using the `.iter().fold()` construct."
msgstr ""
"C++ 와 유사하게 제로 코스트 추상화는 CPU나 메모리를 사용하여 상위레벨 프로그"
"래밍 구조를 만드는데 '비용'을 지불할 필요가 없습니다. 예를 들어 `for` 루프와"
"와 `iter().fold()` 구조를 사용하는 것과 거의 동일한 낮은 수준의 명령어가 생성"
"될 것 입니다."
#: src/why-rust/modern.md:28
msgid ""
"It may be worth mentioning that Rust enums are 'Algebraic Data Types', also "
"known as 'sum types', which allow the type system to express things like "
"`Option<T>` and `Result<T, E>`."
msgstr ""
"러스트의 열거형(enum)은 합계 타입(sum type)으로 알려진 대수학적 데이터형"
"(Algebraic Data Type)으로, 타입 시스템이 `Option<T>`와 `Result<T, E>`등을 표"
"현할 수 있게 해줍니다."
#: src/why-rust/modern.md:32
msgid ""
"Remind people to read the errors --- many developers have gotten used to "
"ignore lengthy compiler output. The Rust compiler is significantly more "
"talkative than other compilers. It will often provide you with _actionable_ "
"feedback, ready to copy-paste into your code."
msgstr ""
"오류를 읽어보시기 바랍니다 --- 오랜기간 많은 개발자들이 컴파일러 출력을 무시"
"하는데 익숙해져 있습니다. 러스트 컴파일러는 다른 컴파일러보다 더 수다스럽고, "
"복사-붙여넣기 할 수 있는 정도의 코드 피드백을 제공하는 경우가 많습니다."
#: src/why-rust/modern.md:37
msgid ""
"The Rust standard library is small compared to languages like Java, Python, "
"and Go. Rust does not come with several things you might consider standard "
"and essential:"
msgstr ""
"러스트 표준 라이브러리는 Java, Python이나 Go와 같은 언어에 비해서 규모가 작습"
"니다. 당연히 포함되어야 한다고 생각할 수도 있는 아래와 같은 것들이 러스트의 "
"표준 라이브러리에 없습니다:"
#: src/why-rust/modern.md:41
msgid "a random number generator, but see [rand](https://docs.rs/rand/)."
msgstr ""
"난수 생성기, 하지만 [rand](https://docs.rs/rand/)문서를 참조하시기 바랍니다."
#: src/why-rust/modern.md:42
msgid "support for SSL or TLS, but see [rusttls](https://docs.rs/rustls/)."
msgstr ""
"SSL 또는 TLS지원, 하지만 [rusttls](https://docs.rs/rustls/)문서를 참조하시기 "
"바랍니다."
#: src/why-rust/modern.md:43
msgid "support for JSON, but see [serde_json](https://docs.rs/serde_json/)."
msgstr ""
"JSON 지원, 하지만 [serde_json](https://docs.rs/serde_json/) 문서를 참조하시"
"기 바랍니다."
#: src/why-rust/modern.md:45
msgid ""
"The reasoning behind this is that functionality in the standard library "
"cannot go away, so it has to be very stable. For the examples above, the "
"Rust community is still working on finding the best solution --- and perhaps "
"there isn't a single \"best solution\" for some of these things."
msgstr ""
"그 이유는 표준 라이브러리에서 한 번 어떤 기능을 제공하면 뺄 수 없으며, 매우 "
"안정적이어야 하기 때문입니다. 위에 언급한 기능들은 아직 러스트 커뮤니티가 최"
"고의 솔루션을 찾지 못했기 때문에 표준 라이브러리에 포함되지 않았습니다. 어쩌"
"면 이들 중 몇 개는 '최고의 솔루션'이 아예 존재할 수 없을 지도 모릅니다."
#: src/why-rust/modern.md:50
msgid ""
"Rust comes with a built-in package manager in the form of Cargo and this "
"makes it trivial to download and compile third-party crates. A consequence "
"of this is that the standard library can be smaller."
msgstr ""
"러스트는 카고라는 패키지 관리자가 내장되어 있고, 서드파티 크레이트를 다운로"
"드, 컴파일 하기 매우 쉽습니다. 이 또한 표준 라이브러리가 작은 이유입니다."
#: src/why-rust/modern.md:54
msgid ""
"Discovering good third-party crates can be a problem. Sites like <https://"
"lib.rs/> help with this by letting you compare health metrics for crates to "
"find a good and trusted one."
msgstr ""
"좋은 서드파티 크레이트를 찾는 것은 어렵습니다. <https://lib.rs> 와 같은 사이"
"트가 신뢰할수 있는 좋은 크레이트를 비교하여 찾는데 좋습니다."
#: src/why-rust/modern.md:58
msgid ""
"[rust-analyzer](https://rust-analyzer.github.io/) is a well supported LSP "
"implementation used in major IDEs and text editors."
msgstr ""
"[rust-analyzer](https://rust-analyzer.github.io/)는 주요 IDE나 텍스트 에디터"
"에서 사용되는 러스트용 LSP서버 입니다."
#: src/basic-syntax.md:3
msgid "Much of the Rust syntax will be familiar to you from C, C++ or Java:"
msgstr "대부분의 러스트 문법은 C/C++/Java 와 유사합니다:"
#: src/basic-syntax.md:5
msgid "Blocks and scopes are delimited by curly braces."
msgstr "블록과 범위는 중괄호`{}`로 표현합니다."
#: src/basic-syntax.md:6
msgid ""
"Line comments are started with `//`, block comments are delimited by `/* ... "
"*/`."
msgstr "인라인 주석은 `//`, 블록 주석은 `/* ... */`로 사용합니다."
#: src/basic-syntax.md:8
msgid "Keywords like `if` and `while` work the same."
msgstr "`if`나 `while`같은 키워드도 동일합니다."
#: src/basic-syntax.md:9
msgid "Variable assignment is done with `=`, comparison is done with `==`."
msgstr "변수 할당은 `=`, 비교는 `==`를 사용합니다."
#: src/basic-syntax/scalar-types.md:3 src/basic-syntax/compound-types.md:3
#: src/exercises/day-3/safe-ffi-wrapper.md:16
msgid "Types"
msgstr "타입"
#: src/basic-syntax/scalar-types.md:3 src/basic-syntax/compound-types.md:3
msgid "Literals"
msgstr "리터럴 값"
#: src/basic-syntax/scalar-types.md:5
msgid "Signed integers"
msgstr "부호있는 정수"
#: src/basic-syntax/scalar-types.md:5
msgid "`i8`, `i16`, `i32`, `i64`, `i128`, `isize`"
msgstr "`i8`, `i16`, `i32`, `i64`, `i128`, `isize`"
#: src/basic-syntax/scalar-types.md:5
msgid "`-10`, `0`, `1_000`, `123_i64`"
msgstr "`-10`, `0`, `1_000`, `123_i64`"
#: src/basic-syntax/scalar-types.md:6
msgid "Unsigned integers"
msgstr "부호없는 정수"
#: src/basic-syntax/scalar-types.md:6
msgid "`u8`, `u16`, `u32`, `u64`, `u128`, `usize`"
msgstr "`u8`, `u16`, `u32`, `u64`, `u128`, `usize`"
#: src/basic-syntax/scalar-types.md:6
msgid "`0`, `123`, `10_u16`"
msgstr "`0`, `123`, `10_u16`"
#: src/basic-syntax/scalar-types.md:7
msgid "Floating point numbers"
msgstr "부동소수"
#: src/basic-syntax/scalar-types.md:7
msgid "`f32`, `f64`"
msgstr "`f32`, `f64`"
#: src/basic-syntax/scalar-types.md:7
msgid "`3.14`, `-10.0e20`, `2_f32`"
msgstr "`3.14`, `-10.0e20`, `2_f32`"
#: src/basic-syntax/scalar-types.md:8
msgid "Strings"
msgstr "문자열"
#: src/basic-syntax/scalar-types.md:8
msgid "`&str`"
msgstr "`&str`"
#: src/basic-syntax/scalar-types.md:8
msgid "`\"foo\"`, `\"two\\nlines\"`"
msgstr "`\"foo\"`, `\"two\\nlines\"`"
#: src/basic-syntax/scalar-types.md:9
msgid "Unicode scalar values"
msgstr "유니코드 문자"
#: src/basic-syntax/scalar-types.md:9
msgid "`char`"
msgstr "`char`"
#: src/basic-syntax/scalar-types.md:9
msgid "`'a'`, `'α'`, `'∞'`"
msgstr "`'a'`, `'α'`, `'∞'`"
#: src/basic-syntax/scalar-types.md:10
msgid "Booleans"
msgstr "불리언"
#: src/basic-syntax/scalar-types.md:10
msgid "`bool`"
msgstr "`bool`"
#: src/basic-syntax/scalar-types.md:10
msgid "`true`, `false`"
msgstr "`true`, `false`"
#: src/basic-syntax/scalar-types.md:12
msgid "The types have widths as follows:"
msgstr "각 타입의 크기는 다음과 같습니다:"
#: src/basic-syntax/scalar-types.md:14
msgid "`iN`, `uN`, and `fN` are _N_ bits wide,"
msgstr "`iN`, `uN`, `fN`은 모두 _N_비트 입니다."
#: src/basic-syntax/scalar-types.md:15
msgid "`isize` and `usize` are the width of a pointer,"
msgstr "`isize` 와 `usize` 는 포인터와 같은 크기입니다,"
#: src/basic-syntax/scalar-types.md:16
msgid "`char` is 32 bits wide,"
msgstr "`char` 32 비트 입니다,"
#: src/basic-syntax/scalar-types.md:17
msgid "`bool` is 8 bits wide."
msgstr "`bool`은 8 비트 입니다."
#: src/basic-syntax/scalar-types.md:21
msgid "There are a few syntaxes which are not shown above:"
msgstr "위에 표시되지 않은 몇 가지 문법이 있습니다:"
#: src/basic-syntax/scalar-types.md:23
msgid ""
"Raw strings allow you to create a `&str` value with escapes disabled: "
"`r\"\\n\" == \"\\\\n\"`. You can embed double-quotes by using an equal "
"amount of `#` on either side of the quotes:"
msgstr ""
"Raw strings allow you to create a `&str` value with escapes disabled: "
"`r\"\\n\" == \"\\\\n\"`. You can embed double-quotes by using an equal "
"amount of `#` on either side of the quotes:"
#: src/basic-syntax/scalar-types.md:27
msgid ""
"```rust,editable\n"
"fn main() {\n"
" println!(r#\"<a href=\"link.html\">link</a>\"#);\n"
" println!(\"<a href=\\\"link.html\\\">link</a>\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" println!(r#\"<a href=\"link.html\">link</a>\"#);\n"
" println!(\"<a href=\\\"link.html\\\">link</a>\");\n"
"}\n"
"```"
#: src/basic-syntax/scalar-types.md:34
msgid "Byte strings allow you to create a `&[u8]` value directly:"
msgstr "Byte strings allow you to create a `&[u8]` value directly:"
#: src/basic-syntax/scalar-types.md:36
msgid ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"{:?}\", b\"abc\");\n"
" println!(\"{:?}\", &[97, 98, 99]);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"{:?}\", b\"abc\");\n"
" println!(\"{:?}\", &[97, 98, 99]);\n"
"}\n"
"```"
#: src/basic-syntax/scalar-types.md:43
msgid ""
"All underscores in numbers can be left out, they are for legibility only. So "
"`1_000` can be written as `1000` (or `10_00`), and `123_i64` can be written "
"as `123i64`."
msgstr ""
"All underscores in numbers can be left out, they are for legibility only. So "
"`1_000` can be written as `1000` (or `10_00`), and `123_i64` can be written "
"as `123i64`."
#: src/basic-syntax/compound-types.md:5
msgid "Arrays"
msgstr "배열"
#: src/basic-syntax/compound-types.md:5
msgid "`[T; N]`"
msgstr "`[T; N]`"
#: src/basic-syntax/compound-types.md:5
msgid "`[20, 30, 40]`, `[0; 3]`"
msgstr "`[20, 30, 40]`, `[0; 3]`"
#: src/basic-syntax/compound-types.md:6
msgid "Tuples"
msgstr "튜플"
#: src/basic-syntax/compound-types.md:6
msgid "`()`, `(T,)`, `(T1, T2)`, ..."
msgstr "`()`, `(T,)`, `(T1, T2)`, ..."
#: src/basic-syntax/compound-types.md:6
msgid "`()`, `('x',)`, `('x', 1.2)`, ..."
msgstr "`()`, `('x',)`, `('x', 1.2)`, ..."
#: src/basic-syntax/compound-types.md:8
msgid "Array assignment and access:"
msgstr "배열 선언과 접근:"
#: src/basic-syntax/compound-types.md:10
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut a: [i8; 10] = [42; 10];\n"
" a[5] = 0;\n"
" println!(\"a: {:?}\", a);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut a: [i8; 10] = [42; 10];\n"
" a[5] = 0;\n"
" println!(\"a: {:?}\", a);\n"
"}\n"
"```"
#: src/basic-syntax/compound-types.md:18
msgid "Tuple assignment and access:"
msgstr "튜플 선언과 접근:"
#: src/basic-syntax/compound-types.md:20
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let t: (i8, bool) = (7, true);\n"
" println!(\"1st index: {}\", t.0);\n"
" println!(\"2nd index: {}\", t.1);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let t: (i8, bool) = (7, true);\n"
" println!(\"1st index: {}\", t.0);\n"
" println!(\"2nd index: {}\", t.1);\n"
"}\n"
"```"
#: src/basic-syntax/compound-types.md:32
msgid "Arrays:"
msgstr "배열:"
#: src/basic-syntax/compound-types.md:34
msgid ""
"A value of the array type `[T; N]` holds `N` (a compile-time constant) "
"elements of the same type `T`. Note that the length of the array is _part of "
"its type_, which means that `[u8; 3]` and `[u8; 4]` are considered two "
"different types."
msgstr ""
"배열은, 같은 타입 `T`의 값이 `N`개 있는 것입니다. 여기서 `N`은 컴파일 타임에 "
"결정된 값이어야 합니다. 이 길이도 타입의 일부입니다. 따라서, `[u8; 3]`와 "
"`[u8; 4]`은 서로 다른 타입입니다."
#: src/basic-syntax/compound-types.md:38
msgid "We can use literals to assign values to arrays."
msgstr "리터럴을 사용하여 배열에 값을 할당할 수 있습니다."
#: src/basic-syntax/compound-types.md:40
msgid ""
"In the main function, the print statement asks for the debug implementation "
"with the `?` format parameter: `{}` gives the default output, `{:?}` gives "
"the debug output. We could also have used `{a}` and `{a:?}` without "
"specifying the value after the format string."
msgstr ""
"포매팅 문자열에서 `?`는 디버깅 출력을 의미합니다. `{}`는 기본 출력이며, `{:?}"
"`는 디버깅 출력입니다. `{a}`, `{a:?}`와 같이 출력할 변수 이름을 포매팅 문자열"
"에 포함시킬 수도 있으며, 이 경우 인자 `a`는 별도의 인자로 추가하지 않습니다."
#: src/basic-syntax/compound-types.md:45
msgid ""
"Adding `#`, eg `{a:#?}`, invokes a \"pretty printing\" format, which can be "
"easier to read."
msgstr ""
"`#`을 추가하면(`{a:#?}`) 좀 더 읽기 쉬운 \"이쁜\" 형태로 출력이 됩니다."
#: src/basic-syntax/compound-types.md:47
msgid "Tuples:"
msgstr "튜플:"
#: src/basic-syntax/compound-types.md:49
msgid "Like arrays, tuples have a fixed length."
msgstr "배열과 마찬가지로 튜플은 고정 길이를 갖습니다."
#: src/basic-syntax/compound-types.md:51
msgid "Tuples group together values of different types into a compound type."
msgstr "튜플은 서로 다른 타입의 값들을 하나의 복합 타입으로 묶습니다."
#: src/basic-syntax/compound-types.md:53
msgid ""
"Fields of a tuple can be accessed by the period and the index of the value, "
"e.g. `t.0`, `t.1`."
msgstr "튜플에 속한 값은 `t.0`, `t.1`과 같이 인덱스로 접근할 수 있습니다."
#: src/basic-syntax/compound-types.md:55
msgid ""
"The empty tuple `()` is also known as the \"unit type\". It is both a type, "
"and the only valid value of that type - that is to say both the type and its "
"value are expressed as `()`. It is used to indicate, for example, that a "
"function or expression has no return value, as we'll see in a future slide. "
msgstr ""
"비어있는 튜플`()`은 단위 타입(unit type)이라고도 합니다. 이는 타입이면서 해"
"당 타입의 유일하며 유효한 값입니다. 즉 타입과 값이 모두 `()`입니다. 예를 들"
"어 함수나 식에서 반환 값이 없음을 나타낼 때 사용합니다. "
#: src/basic-syntax/compound-types.md:59
msgid ""
"You can think of it as `void` that can be familiar to you from other "
"programming languages."
msgstr "다른 언어에서 익숙한 `void` 개념으로 생각할 수 있습니다."
#: src/basic-syntax/references.md:3
msgid "Like C++, Rust has references:"
msgstr "C++와 마찬가지로 러스트도 참조형을 갖습니다:"
#: src/basic-syntax/references.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut x: i32 = 10;\n"
" let ref_x: &mut i32 = &mut x;\n"
" *ref_x = 20;\n"
" println!(\"x: {x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut x: i32 = 10;\n"
" let ref_x: &mut i32 = &mut x;\n"
" *ref_x = 20;\n"
" println!(\"x: {x}\");\n"
"}\n"
"```"
#: src/basic-syntax/references.md:14
msgid "Some notes:"
msgstr "참고사항:"
#: src/basic-syntax/references.md:16
msgid ""
"We must dereference `ref_x` when assigning to it, similar to C and C++ "
"pointers."
msgstr ""
"`ref_x`에 값을 할당할 때, C/C++의 포인터와 유사하게 `*`를 이용해서 참조를 따"
"라가야(역참조) 합니다."
#: src/basic-syntax/references.md:17
msgid ""
"Rust will auto-dereference in some cases, in particular when invoking "
"methods (try `ref_x.count_ones()`)."
msgstr ""
"러스트는 특정한 경우(메서드 호출)에 자동으로 역참조를 합니다.(`ref_x."
"count_one()`을 하면 `*ref_x`가 `count_one`의 인자로 전달됩니다.)"
#: src/basic-syntax/references.md:19
msgid ""
"References that are declared as `mut` can be bound to different values over "
"their lifetime."
msgstr ""
"`mut`로 선언된 참조는 그 변수가 살아있는 동안 다른 값을 가질 수 있습니다."
#: src/basic-syntax/references.md:25
msgid ""
"Be sure to note the difference between `let mut ref_x: &i32` and `let ref_x: "
"&mut i32`. The first one represents a mutable reference which can be bound "
"to different values, while the second represents a reference to a mutable "
"value."
msgstr ""
"`let mut ref_x: &i32`와 `let ref_x: &mut i32`의 차이점에 주의 하시기 바랍니"
"다. 첫번째 값은 다른 값에 바인딩 될 수 있는 가변 참조이고, 두번째 값은 가변 "
"값에 대한 참조입니다."
#: src/basic-syntax/references-dangling.md:3
msgid "Rust will statically forbid dangling references:"
msgstr "러스트는 허상(dangling) 참조를 컴파일러 단계에서 찾아내고 금지합니다:"
#: src/basic-syntax/references-dangling.md:5
msgid ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let ref_x: &i32;\n"
" {\n"
" let x: i32 = 10;\n"
" ref_x = &x;\n"
" }\n"
" println!(\"ref_x: {ref_x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let ref_x: &i32;\n"
" {\n"
" let x: i32 = 10;\n"
" ref_x = &x;\n"
" }\n"
" println!(\"ref_x: {ref_x}\");\n"
"}\n"
"```"
#: src/basic-syntax/references-dangling.md:16
msgid "A reference is said to \"borrow\" the value it refers to."
msgstr "참조는 어떤 값을 \"빌리는\" 것입니다."
#: src/basic-syntax/references-dangling.md:17
msgid ""
"Rust is tracking the lifetimes of all references to ensure they live long "
"enough."
msgstr ""
"러스트는 참조 대상의 값이, 그 값에 대한 모든 참조들보다 더 오래 살아있음을 추"
"적합니다."
#: src/basic-syntax/references-dangling.md:19
msgid "We will talk more about borrowing when we get to ownership."
msgstr ""
"소유권에 대한 주제를 다룰 때 이 빌림에 대해 더 자세히 이야기 하겠습니다."
#: src/basic-syntax/slices.md:3
msgid "A slice gives you a view into a larger collection:"
msgstr "슬라이스는 큰 컬랙션의 일부(혹은 전체)를 보여주는 뷰(view)입니다:"
#: src/basic-syntax/slices.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut a: [i32; 6] = [10, 20, 30, 40, 50, 60];\n"
" println!(\"a: {a:?}\");\n"
"\n"
" let s: &[i32] = &a[2..4];\n"
"\n"
" println!(\"s: {s:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let a: [i32; 6] = [10, 20, 30, 40, 50, 60];\n"
" println!(\"a: {a:?}\");\n"
"\n"
" let s: &[i32] = &a[2..4];\n"
" println!(\"s: {s:?}\");\n"
"}\n"
"```"
#: src/basic-syntax/slices.md:16
msgid "Slices borrow data from the sliced type."
msgstr "슬라이스는 다른(슬라이스 된) 타입으로부터 데이터를 '빌려'옵니다."
#: src/basic-syntax/slices.md:17
msgid "Question: What happens if you modify `a[3]` right before printing `s`?"
msgstr "질문: `s`를 출력하기 전에 `a[3]`을 수정하면 무슨 일이 있어날까요?"
#: src/basic-syntax/slices.md:21
msgid ""
"We create a slice by borrowing `a` and specifying the starting and ending "
"indexes in brackets."
msgstr ""
"슬라이스는 우선 `a`를 빌린다음, 시작과 끝 인덱스를 브래킷(`[]`)안에 지정해서 "
"만듭니다."
#: src/basic-syntax/slices.md:23
msgid ""
"If the slice starts at index 0, Rust’s range syntax allows us to drop the "
"starting index, meaning that `&a[0..a.len()]` and `&a[..a.len()]` are "
"identical."
msgstr ""
"슬라이스가 인덱스 0부터 시작한다면 시작 인덱스는 생략 가능합니다. 즉 `&a[0.."
"a.len()]`와 `&a[..a.len()]` 는 동일합니다."
#: src/basic-syntax/slices.md:25
msgid ""
"The same is true for the last index, so `&a[2..a.len()]` and `&a[2..]` are "
"identical."
msgstr ""
"마지막 인덱스도 생략 가능합니다. 그래서 `&a[2..a.len()]` 와 `&a[2..]`는 동일"
"합니다."
#: src/basic-syntax/slices.md:27
msgid ""
"To easily create a slice of the full array, we can therefore use `&a[..]`."
msgstr "따라서 전체 배열에 대한 슬라이스는 `&a[..]`가 됩니다."
#: src/basic-syntax/slices.md:29
msgid ""
"`s` is a reference to a slice of `i32`s. Notice that the type of `s` "
"(`&[i32]`) no longer mentions the array length. This allows us to perform "
"computation on slices of different sizes."
msgstr ""
"`s`는 `i32`들로 이루어진 슬라이스에 대한 참조입니다. `s`의 타입(`&[i32]`)에 "
"배열의 크기가 빠져있음에 주목하시기 바랍니다. 즉, 슬라이스를 이용하면 다양한 "
"길이의 데이터를 다룰 수 있습니다."
#: src/basic-syntax/slices.md:31
msgid ""
"Slices always borrow from another object. In this example, `a` has to remain "
"'alive' (in scope) for at least as long as our slice. "
msgstr ""
"슬라이스는 항상 다른 객체로부터 '빌려' 옵니다. 이 예시에서 객체 `a`는 슬라이"
"스 `s`보다 더 오래 살아 있어야만 합니다. "
#: src/basic-syntax/slices.md:33
msgid ""
"The question about modifying `a[3]` can spark an interesting discussion, but "
"the answer is that for memory safety reasons you cannot do it through `a` at "
"this point in the execution, but you can read the data from both `a` and `s` "
"safely. It works before you created the slice, and again after the "
"`println`, when the slice is no longer used. More details will be explained "
"in the borrow checker section."
msgstr ""
"`a[3]`의 값을 바꿀 수 있냐는 질문은 좋은 질문입니다. 여기에 대한 답은 `a`와 "
"`s`를 통해 데이터를 읽을 수는 있지만 수정할 수는 없으며, 이는 메모리 안전을 "
"위해서라는 것입니다. 그런데, 슬라이스가 사용되지 않을 때, 즉 슬라이스를 만들"
"기 전이나, 혹은 `println`이후에는 `a[3]`을 바꿀 수 있습니다. 왜 그런지에 대"
"한 좀더 구체적인 답은 빌림 검사 부분에서 자세히 설명합니다."
#: src/basic-syntax/string-slices.md:1
msgid "`String` vs `str`"
msgstr "`String`과 `str`"
#: src/basic-syntax/string-slices.md:3
msgid "We can now understand the two string types in Rust:"
msgstr "이제 러스트의 두 가지 문자열 타입에 대해서 이해해 보겠습니다:"
#: src/basic-syntax/string-slices.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let s1: &str = \"World\";\n"
" println!(\"s1: {s1}\");\n"
"\n"
" let mut s2: String = String::from(\"Hello \");\n"
" println!(\"s2: {s2}\");\n"
" s2.push_str(s1);\n"
" println!(\"s2: {s2}\");\n"
" \n"
" let s3: &str = &s2[6..];\n"
" println!(\"s3: {s3}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let s1: &str = \"World\";\n"
" println!(\"s1: {s1}\");\n"
"\n"
" let mut s2: String = String::from(\"Hello \");\n"
" println!(\"s2: {s2}\");\n"
" s2.push_str(s1);\n"
" println!(\"s2: {s2}\");\n"
" \n"
" let s3: &str = &s2[6..];\n"
" println!(\"s3: {s3}\");\n"
"}\n"
"```"
#: src/basic-syntax/string-slices.md:20
msgid "Rust terminology:"
msgstr "러스트 용어:"
#: src/basic-syntax/string-slices.md:22
msgid "`&str` an immutable reference to a string slice."
msgstr "`&str`은 문자열 슬라이스에 대한 (불변) 참조입니다."
#: src/basic-syntax/string-slices.md:23
msgid "`String` a mutable string buffer."
msgstr "`String`은 문자열을 담을 수 있는 버퍼입니다."
#: src/basic-syntax/string-slices.md:27
msgid ""
"`&str` introduces a string slice, which is an immutable reference to UTF-8 "
"encoded string data stored in a block of memory. String literals "
"(`”Hello”`), are stored in the program’s binary."
msgstr ""
"`&str`은 문자열 슬라이스입니다. 문자열 슬라이스는 UTF-8로 인코딩된 문자열 데"
"이터를 의미합니다. 문자열 리터럴(`\"Hello\"`)은 프로그램 바이너리에 저장됩니"
"다."
#: src/basic-syntax/string-slices.md:30
msgid ""
"Rust’s `String` type is a wrapper around a vector of bytes. As with a "
"`Vec<T>`, it is owned."
msgstr ""
"러스트의 `String`타입은 실제로는 문자열을 이루는 바이트에 대한 백터"
"(`Vec<u8>`)입니다. `Vec<T>`가 `T`를 소유하고 있듯이, `String`이 가리키고 있"
"는 문자열은 `String`의 소유입니다."
#: src/basic-syntax/string-slices.md:32
msgid ""
"As with many other types `String::from()` creates a string from a string "
"literal; `String::new()` creates a new empty string, to which string data "
"can be added using the `push()` and `push_str()` methods."
msgstr ""
"다른 많은 타입들처럼 `String::from`는 문자열 리터럴로부터 문자열을 생성합니"
"다. `String::new()`는 새로운 빈 문자열을 생성합니다. `push()`와 `push_str()`"
"메서드를 사용하여 문자열 데이터를 추가 할 수 있습니다."
#: src/basic-syntax/string-slices.md:35
msgid ""
"The `format!()` macro is a convenient way to generate an owned string from "
"dynamic values. It accepts the same format specification as `println!()`."
msgstr ""
"`format!()` 매크로는 변수의 값을 문자열로 변환하는 편리한 방법입니다. 이 매크"
"로는 `println!()` 매크로와 동일한 포맷팅 형식을 지원합니다."
#: src/basic-syntax/string-slices.md:38
msgid ""
"You can borrow `&str` slices from `String` via `&` and optionally range "
"selection."
msgstr ""
"`&`와 범위 연산자를 이용하여 `String`에서 `&str`슬라이스를 빌려올 수 있습니"
"다."
#: src/basic-syntax/string-slices.md:40
msgid ""
"For C++ programmers: think of `&str` as `const char*` from C++, but the one "
"that always points to a valid string in memory. Rust `String` is a rough "
"equivalent of `std::string` from C++ (main difference: it can only contain "
"UTF-8 encoded bytes and will never use a small-string optimization)."
msgstr ""
"당신이 C++ 프로그래머 라면: `&str`는 C++의 `const char*`와 유사하지만 항상 유"
"효한 문자열을 가리킨다는 점이 다릅니다. 러스트의 `String`은 C++의 `std::"
"string` 과 대략 거의 동일합니다. (주요 차이점: 러스트의 `String`은 UTF-8 인코"
"딩 바이트만 포함할 수 있으며 작은 문자열 최적화(small-string optimization)는 "
"구현하지 않습니다."
#: src/basic-syntax/functions.md:3
msgid ""
"A Rust version of the famous [FizzBuzz](https://en.wikipedia.org/wiki/"
"Fizz_buzz) interview question:"
msgstr ""
"러스트 버전의 [FizzBuzz](https://en.wikipedia.org/wiki/Fizz_buzz) 함수입니다:"
#: src/basic-syntax/functions.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" print_fizzbuzz_to(20);\n"
"}\n"
"\n"
"fn is_divisible(n: u32, divisor: u32) -> bool {\n"
" if divisor == 0 {\n"
" return false;\n"
" }\n"
" n % divisor == 0\n"
"}\n"
"\n"
"fn fizzbuzz(n: u32) -> String {\n"
" let fizz = if is_divisible(n, 3) { \"fizz\" } else { \"\" };\n"
" let buzz = if is_divisible(n, 5) { \"buzz\" } else { \"\" };\n"
" if fizz.is_empty() && buzz.is_empty() {\n"
" return format!(\"{n}\");\n"
" }\n"
" format!(\"{fizz}{buzz}\")\n"
"}\n"
"\n"
"fn print_fizzbuzz_to(n: u32) {\n"
" for i in 1..=n {\n"
" println!(\"{}\", fizzbuzz(i));\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" print_fizzbuzz_to(20);\n"
"}\n"
"\n"
"fn is_divisible(n: u32, divisor: u32) -> bool {\n"
" if divisor == 0 {\n"
" return false;\n"
" }\n"
" n % divisor == 0\n"
"}\n"
"\n"
"fn fizzbuzz(n: u32) -> String {\n"
" let fizz = if is_divisible(n, 3) { \"fizz\" } else { \"\" };\n"
" let buzz = if is_divisible(n, 5) { \"buzz\" } else { \"\" };\n"
" if fizz.is_empty() && buzz.is_empty() {\n"
" return format!(\"{n}\");\n"
" }\n"
" format!(\"{fizz}{buzz}\")\n"
"}\n"
"\n"
"fn print_fizzbuzz_to(n: u32) {\n"
" for i in 1..=n {\n"
" println!(\"{}\", fizzbuzz(i));\n"
" }\n"
"}\n"
"```"
#: src/basic-syntax/functions.md:35
msgid ""
"We refer in `main` to a function written below. Neither forward declarations "
"nor headers are necessary. "
msgstr ""
"`main` 함수에서 그 다음에 오는 함수들을 사용할 수 있습니다. 미리 선언하기"
"(forward declaration)나 헤더 같은건 필요 없습니다. "
#: src/basic-syntax/functions.md:36
msgid ""
"Declaration parameters are followed by a type (the reverse of some "
"programming languages), then a return type."
msgstr ""
"매개변수를 선언할 때에는 이름을 먼저 쓰고, 타입을 나중에 씁니다. 이름과 타입"
"은 `:` 로 구분합니다. 이는 일부 언어(예를 들어 C)와 반대임에 유의하시기 바랍"
"니다. 마찬가지로, 리턴 타입도 함수의 시작이 아닌 가장 뒷부분에 선언합니다."
#: src/basic-syntax/functions.md:37
msgid ""
"The last expression in a function body (or any block) becomes the return "
"value. Simply omit the `;` at the end of the expression."
msgstr ""
"함수 본문의 마지막 표현식은 반환 값이 됩니다. 간단히, 식 끝에 있는 `;`를 생략"
"하면 됩니다."
#: src/basic-syntax/functions.md:38
msgid ""
"Some functions have no return value, and return the 'unit type', `()`. The "
"compiler will infer this if the `-> ()` return type is omitted."
msgstr ""
"반환값이 없는 함수의 경우, 유닛 타입 `()`을 반환합니다. `-> ()`가 생략된 경"
"우 컴파일러는 이를 추론합니다."
#: src/basic-syntax/functions.md:39
msgid ""
"The range expression in the `for` loop in `print_fizzbuzz_to()` contains "
"`=n`, which causes it to include the upper bound."
msgstr ""
"`fizzbuzz_to()`함수 내 `for` 반목문의 범위 표현식 중 `=n`은 n까지 포함한다는 "
"의미입니다."
#: src/basic-syntax/rustdoc.md:3
msgid ""
"All language items in Rust can be documented using special `///` syntax."
msgstr "Rust의 아이템(item)은 `///` 문법을 사용하여 문서화할 수 있습니다."
#: src/basic-syntax/rustdoc.md:5
msgid ""
"```rust,editable\n"
"/// Determine whether the first argument is divisible by the second "
"argument.\n"
"///\n"
"/// If the second argument is zero, the result is false.\n"
"fn is_divisible_by(lhs: u32, rhs: u32) -> bool {\n"
" if rhs == 0 {\n"
" return false; // Corner case, early return\n"
" }\n"
" lhs % rhs == 0 // The last expression in a block is the return "
"value\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"/// 첫 번째 인수가 두 번째 인수로 나눠질 수 있는지 결정합니다.\n"
"///\n"
"/// 두 번째 인수가 0이면 결과는 false입니다.\n"
"fn is_divisible_by(lhs: u32, rhs: u32) -> bool {\n"
" if rhs == 0 {\n"
" return false; // Corner case, early return\n"
" }\n"
" lhs % rhs == 0 // 블록 안의 마지막 표현식은 반환값입니다\n"
"}\n"
"```"
#: src/basic-syntax/rustdoc.md:17
msgid ""
"The contents are treated as Markdown. All published Rust library crates are "
"automatically documented at [`docs.rs`](https://docs.rs) using the [rustdoc]"
"(https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html) tool. It is "
"idiomatic to document all public items in an API using this pattern."
msgstr ""
"콘텐츠는 마크다운으로 처리됩니다. 게시된 모든 Rust 라이브러리 크레이트는 "
"[rustdoc](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html) 도구를 사용"
"하여 [`docs.rs`](https://docs.rs)에 자동으로 문서화됩니다. 일반적으로 API의 "
"모든 공개 항목은 이 패턴을 사용하여 문서화됩니다."
#: src/basic-syntax/rustdoc.md:24
msgid ""
"Show students the generated docs for the `rand` crate at [`docs.rs/rand`]"
"(https://docs.rs/rand)."
msgstr ""
"[`docs.rs/rand`](https://docs.rs/rand)에서 `rand` 크레이트용으로 생성된 문서"
"를 보여줍니다."
#: src/basic-syntax/rustdoc.md:27
msgid ""
"This course does not include rustdoc on slides, just to save space, but in "
"real code they should be present."
msgstr ""
"이 슬라이드의 예제 코드는 문서화 주석이 생략되어 있지만, 실제 코드라면 문서"
"화 주석을 반드시 써야 합니다."
#: src/basic-syntax/rustdoc.md:30
msgid ""
"Inner doc comments are discussed later (in the page on modules) and need not "
"be addressed here."
msgstr ""
"문서 내부 주석 모듈 페이지 뒷부분에서 다루며 여기서 다루지 않아도 됩니다."
#: src/basic-syntax/rustdoc.md:33
msgid ""
"Rustdoc comments can contain code snippets that we can run and test using "
"`cargo test`. We will discuss these tests in the [Testing section](../"
"testing/doc-tests.html)."
msgstr ""
"문서화 주석은 코드를 포함할 수도 있으며, 이 코드는 `cargo test`를 통해 테스트"
"로 동작할 수도 있습니다. [테스트](../testing/doc-tests.html)에서 더 자세히 다"
"루겠습니다."
#: src/basic-syntax/methods.md:3
msgid ""
"Methods are functions associated with a type. The `self` argument of a "
"method is an instance of the type it is associated with:"
msgstr ""
"메서드는 특정 타입과 연결된 함수입니다. 메서드의 `self` 인자가 그 메서드가 연"
"결된 인스턴스의 타입입니다:"
#: src/basic-syntax/methods.md:6
msgid ""
"```rust,editable\n"
"struct Rectangle {\n"
" width: u32,\n"
" height: u32,\n"
"}\n"
"\n"
"impl Rectangle {\n"
" fn area(&self) -> u32 {\n"
" self.width * self.height\n"
" }\n"
"\n"
" fn inc_width(&mut self, delta: u32) {\n"
" self.width += delta;\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let mut rect = Rectangle { width: 10, height: 5 };\n"
" println!(\"old area: {}\", rect.area());\n"
" rect.inc_width(5);\n"
" println!(\"new area: {}\", rect.area());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"struct Rectangle {\n"
" width: u32,\n"
" height: u32,\n"
"}\n"
"\n"
"impl Rectangle {\n"
" fn area(&self) -> u32 {\n"
" self.width * self.height\n"
" }\n"
"\n"
" fn inc_width(&mut self, delta: u32) {\n"
" self.width += delta;\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let mut rect = Rectangle { width: 10, height: 5 };\n"
" println!(\"old area: {}\", rect.area());\n"
" rect.inc_width(5);\n"
" println!(\"new area: {}\", rect.area());\n"
"}\n"
"```"
#: src/basic-syntax/methods.md:30
msgid ""
"We will look much more at methods in today's exercise and in tomorrow's "
"class."
msgstr "오늘과 내일 강의에서 더 많은 메서드 사용법을 다룰 것입니다."
#: src/basic-syntax/methods.md:34
msgid "Add a static method called `Rectangle::new` and call this from `main`:"
msgstr "`Rectangle::new` 생성자를 추가하고 이를 `main`에서 호출합니다:"
#: src/basic-syntax/methods.md:36
msgid ""
"```rust,editable,compile_fail\n"
"fn new(width: u32, height: u32) -> Rectangle {\n"
" Rectangle { width, height }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"fn new(width: u32, height: u32) -> Rectangle {\n"
" Rectangle { width, height }\n"
"}\n"
"```"
#: src/basic-syntax/methods.md:42
msgid ""
"While _technically_, Rust does not have custom constructors, static methods "
"are commonly used to initialize structs (but don't have to). The actual "
"constructor, `Rectangle { width, height }`, could be called directly. See "
"the [Rustnomicon](https://doc.rust-lang.org/nomicon/constructors.html)."
msgstr ""
"\\_기술적_으로 이야기 하자면, 러스트는 커스텀 생성자를 지원하지 않습니다. 정"
"적 메소드를 사용하는 것이 구조체를 초기화 하는 일반적인 방법입니다 (물론 이것"
"이 강제되지는 않습니다). 진짜 생성자인 `Rectangle { width, height }`를 직접 "
"호출할 수도 있습니다. 자세한 내용은 [Rustnomicon](https://doc.rust-lang.org/"
"nomicon/constructors.html)을 참조하세요."
#: src/basic-syntax/methods.md:45
msgid ""
"Add a `Rectangle::square(width: u32)` constructor to illustrate that such "
"static methods can take arbitrary parameters."
msgstr ""
"`Rectangle::square(width: u32)` 생성자를 추가하여 생성자가 임의의 매개변수를 "
"사용할 수 있음을 보입시다."
#: src/basic-syntax/functions-interlude.md:1
msgid "Function Overloading"
msgstr "(함수) 오버로딩"
#: src/basic-syntax/functions-interlude.md:3
msgid "Overloading is not supported:"
msgstr "오버로딩은 지원되지 않습니다:"
#: src/basic-syntax/functions-interlude.md:5
msgid "Each function has a single implementation:"
msgstr "개별함수는 단일 구현만 갖습니다:"
#: src/basic-syntax/functions-interlude.md:6
msgid "Always takes a fixed number of parameters."
msgstr "항상 고정된 수의 파라매터만 갖습니다."
#: src/basic-syntax/functions-interlude.md:7
msgid "Always takes a single set of parameter types."
msgstr "파라매터들의 타입은 항상 고정되어 있습니다."
#: src/basic-syntax/functions-interlude.md:8
msgid "Default values are not supported:"
msgstr "파라매터의 기본 값은 지원되지 않습니다:"
#: src/basic-syntax/functions-interlude.md:9
msgid "All call sites have the same number of arguments."
msgstr "모든 호출부에서는 동일한 수의 인자를 설정해야합니다."
#: src/basic-syntax/functions-interlude.md:10
msgid "Macros are sometimes used as an alternative."
msgstr "이런 사항들이 제약이 될 경우, 대안으로 매크로를 사용하기도 합니다."
#: src/basic-syntax/functions-interlude.md:12
msgid "However, function parameters can be generic:"
msgstr "하지만, 함수의 매개변수는 제네릭을 적용할 수 있습니다:"
#: src/basic-syntax/functions-interlude.md:14
msgid ""
"```rust,editable\n"
"fn pick_one<T>(a: T, b: T) -> T {\n"
" if std::process::id() % 2 == 0 { a } else { b }\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"coin toss: {}\", pick_one(\"heads\", \"tails\"));\n"
" println!(\"cash prize: {}\", pick_one(500, 1000));\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn pick_one<T>(a: T, b: T) -> T {\n"
" if std::process::id() % 2 == 0 { a } else { b }\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"coin toss: {}\", pick_one(\"heads\", \"tails\"));\n"
" println!(\"cash prize: {}\", pick_one(500, 1000));\n"
"}\n"
"```"
#: src/basic-syntax/functions-interlude.md:27
msgid ""
"When using generics, the standard library's `Into<T>` can provide a kind of "
"limited polymorphism on argument types. We will see more details in a later "
"section."
msgstr ""
"제네릭을 사용할 때 표준 라이브러리의 `Into<T>`은 타입에 대한 다형성을 제공할 "
"수 있습니다. 나중에 자세히 설명하겠습니다."
#: src/exercises/day-1/morning.md:1
msgid "Day 1: Morning Exercises"
msgstr "1일차 오전 연습문제"
#: src/exercises/day-1/morning.md:3
msgid "In these exercises, we will explore two parts of Rust:"
msgstr "이번 연습문제는 러스트의 두 부분을 알아볼 것입니다:"
#: src/exercises/day-1/morning.md:5
msgid "Implicit conversions between types."
msgstr "타입의 묵시적 변환."
#: src/exercises/day-1/morning.md:7
msgid "Arrays and `for` loops."
msgstr "배열과 `for` 반복문."
#: src/exercises/day-1/morning.md:11
msgid "A few things to consider while solving the exercises:"
msgstr "연습문제를 해결하는데 고려해야 할 사항들:"
#: src/exercises/day-1/morning.md:13
msgid ""
"Use a local Rust installation, if possible. This way you can get auto-"
"completion in your editor. See the page about [Using Cargo](../../cargo.md) "
"for details on installing Rust."
msgstr ""
"가능하다면 러스트가 설치된 로컬 환경에서 진행하세요. 그러는 편이 텍스트 에디"
"터의 자동완성 기능의 도움을 받을 수 있어서 좋습니다. [카고 사용하기](../../"
"cargo.md) 을 참조하시기 바랍니다."
#: src/exercises/day-1/morning.md:17
msgid "Alternatively, use the Rust Playground."
msgstr "혹은 러스트 플레이그라운드를 이용할 수 있습니다."
#: src/exercises/day-1/morning.md:19
msgid ""
"The code snippets are not editable on purpose: the inline code snippets lose "
"their state if you navigate away from the page."
msgstr ""
"페이지 밖으로 이동할 경우 작성한 내용이 소실되기 때문에 제공되는 코드 스니펫"
"은 의도적으로 편집할 수 없습니다."
#: src/exercises/day-1/morning.md:22 src/exercises/day-1/afternoon.md:11
#: src/exercises/day-2/morning.md:11 src/exercises/day-2/afternoon.md:7
#: src/exercises/day-3/morning.md:7 src/exercises/bare-metal/morning.md:7
#: src/exercises/bare-metal/afternoon.md:7
#: src/exercises/concurrency/morning.md:12
#: src/exercises/concurrency/afternoon.md:13
msgid ""
"After looking at the exercises, you can look at the \\[solutions\\] provided."
msgstr ""
"연습문제를 살펴 본 후, 제공된 \\[해답\\]\\[solutions\\]을 살펴볼 수 있습니다."
#: src/exercises/day-1/implicit-conversions.md:3
msgid ""
"Rust will not automatically apply _implicit conversions_ between types "
"([unlike C++](https://en.cppreference.com/w/cpp/language/"
"implicit_conversion)). You can see this in a program like this:"
msgstr ""
"러스트는 [C++ 와 다르게](https://en.cppreference.com/w/cpp/language/"
"implicit_conversion) 타입 간 _묵시적 변환_을 자동으로 적용하지 않습니다. 아"
"래 예시를 확인해 보세요:"
#: src/exercises/day-1/implicit-conversions.md:6
msgid ""
"```rust,editable,compile_fail\n"
"fn multiply(x: i16, y: i16) -> i16 {\n"
" x * y\n"
"}\n"
"\n"
"fn main() {\n"
" let x: i8 = 15;\n"
" let y: i16 = 1000;\n"
"\n"
" println!(\"{x} * {y} = {}\", multiply(x, y));\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"fn multiply(x: i16, y: i16) -> i16 {\n"
" x * y\n"
"}\n"
"\n"
"fn main() {\n"
" let x: i8 = 15;\n"
" let y: i16 = 1000;\n"
"\n"
" println!(\"{x} * {y} = {}\", multiply(x, y));\n"
"}\n"
"```"
#: src/exercises/day-1/implicit-conversions.md:19
msgid ""
"The Rust integer types all implement the [`From<T>`](https://doc.rust-lang."
"org/std/convert/trait.From.html) and [`Into<T>`](https://doc.rust-lang.org/"
"std/convert/trait.Into.html) traits to let us convert between them. The "
"`From<T>` trait has a single `from()` method and similarly, the `Into<T>` "
"trait has a single `into()` method. Implementing these traits is how a type "
"expresses that it can be converted into another type."
msgstr ""
"러스트의 정수형 타입은 모두 [`From<T>`](https://doc.rust-lang.org/std/"
"convert/trait.From.html) 와 [`Into<T>`](https://doc.rust-lang.org/std/"
"convert/trait.Into.html) 트레잇을 구현하고 있으며, 이를 통해 타입 변환이 이루"
"어 집니다. `From<T>` 트레잇은 `from()` 메서드를 가지고 있고, `Into<T>`트레잇"
"은 `into()` 메서드를 가지고 있습니다. 러스트에서는 `From`과 `Into` 트레잇을 "
"구현함으로써, 타입 간 변환이 가능하다는 것을 표현합니다."
#: src/exercises/day-1/implicit-conversions.md:25
msgid ""
"The standard library has an implementation of `From<i8> for i16`, which "
"means that we can convert a variable `x` of type `i8` to an `i16` by "
"calling `i16::from(x)`. Or, simpler, with `x.into()`, because `From<i8> for "
"i16` implementation automatically create an implementation of `Into<i16> for "
"i8`."
msgstr ""
"표준 라이브러리에는 `From<i8> for i16`가 구현되어 있는데 이것은 `i8` 타입의 "
"변수 `x`를 `i16::from(x)`를 호출하여 `i16`타입으로 변환할 수 있다는 의미입니"
"다. 혹은 더 간단하게 `x.into()`를 사용할 수도 있습니다. 이것이 가능한 이유는 "
"`From<i8> for i16` 구현을 가지고 있으면 `Into<i16> for i8` 구현이 자동으로 생"
"성되기 때문입니다."
#: src/exercises/day-1/implicit-conversions.md:30
msgid ""
"The same applies for your own `From` implementations for your own types, so "
"it is sufficient to only implement `From` to get a respective `Into` "
"implementation automatically."
msgstr ""
"이는 사용자 정의 타입에도 동일하게 적용되는 규칙입니다. 따라서 `From`만을 구"
"현해도 `Into`까지 자동으로 구현이 됩니다."
#: src/exercises/day-1/implicit-conversions.md:33
msgid "Execute the above program and look at the compiler error."
msgstr "위 예제코드를 실행하고 어떤 컴파일 에러가 발생하는지 확인해 보세요."
#: src/exercises/day-1/implicit-conversions.md:35
msgid "Update the code above to use `into()` to do the conversion."
msgstr "`into()`를 사용하여 코드를 수정하세요."
#: src/exercises/day-1/implicit-conversions.md:37
msgid ""
"Change the types of `x` and `y` to other things (such as `f32`, `bool`, "
"`i128`) to see which types you can convert to which other types. Try "
"converting small types to big types and the other way around. Check the "
"[standard library documentation](https://doc.rust-lang.org/std/convert/trait."
"From.html) to see if `From<T>` is implemented for the pairs you check."
msgstr ""
"`x`와 `y`를 `f32`이나 `bool`, `i128` 등으로 바꿔서 해당 타입들로 변환이 되는"
"지 확인해보세요. 작은 사이즈 타입에서 큰 사이즈로 변경해보시고 그 반대로도 해"
"보세요. [표준 라이브러리 문서](https://doc.rust-lang.org/std/convert/trait."
"From.html)에서 시도해 본 케이스가 구현되어 있는지 확인해 보세요."
#: src/exercises/day-1/for-loops.md:1
#: src/exercises/day-1/solutions-morning.md:3
msgid "Arrays and `for` Loops"
msgstr "배열과 `for`반복문"
#: src/exercises/day-1/for-loops.md:3
msgid "We saw that an array can be declared like this:"
msgstr "배열을 아래와 같이 선언 할 수 있음을 배웠습니다:"
#: src/exercises/day-1/for-loops.md:5
msgid ""
"```rust\n"
"let array = [10, 20, 30];\n"
"```"
msgstr ""
"```rust\n"
"let array = [10, 20, 30];\n"
"```"
#: src/exercises/day-1/for-loops.md:9
msgid ""
"You can print such an array by asking for its debug representation with `{:?}"
"`:"
msgstr "배열을 출력하려면 `{:?}`를 씁니다:"
#: src/exercises/day-1/for-loops.md:11
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let array = [10, 20, 30];\n"
" println!(\"array: {array:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let array = [10, 20, 30];\n"
" println!(\"array: {array:?}\");\n"
"}\n"
"```"
#: src/exercises/day-1/for-loops.md:18
msgid ""
"Rust lets you iterate over things like arrays and ranges using the `for` "
"keyword:"
msgstr "러스트에서는 `for` 키워드를 사용해 배열이나 범위를 반복할 수 있습니다:"
#: src/exercises/day-1/for-loops.md:21
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let array = [10, 20, 30];\n"
" print!(\"Iterating over array:\");\n"
" for n in array {\n"
" print!(\" {n}\");\n"
" }\n"
" println!();\n"
"\n"
" print!(\"Iterating over range:\");\n"
" for i in 0..3 {\n"
" print!(\" {}\", array[i]);\n"
" }\n"
" println!();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let array = [10, 20, 30];\n"
" print!(\"Iterating over array:\");\n"
" for n in array {\n"
" print!(\" {n}\");\n"
" }\n"
" println!();\n"
"\n"
" print!(\"Iterating over range:\");\n"
" for i in 0..3 {\n"
" print!(\" {}\", array[i]);\n"
" }\n"
" println!();\n"
"}\n"
"```"
#: src/exercises/day-1/for-loops.md:38
msgid ""
"Use the above to write a function `pretty_print` which pretty-print a matrix "
"and a function `transpose` which will transpose a matrix (turn rows into "
"columns):"
msgstr ""
"위 코드를 이용해서, 행렬을 예쁘게 출력하는 `pretty_print`함수와, 행렬을 전치"
"(행과 열을 서로 바꾸는)시키는 `transpose`함수를 작성해 보시기 바랍니다:"
#: src/exercises/day-1/for-loops.md:41
msgid ""
"```bob\n"
" ⎛⎡1 2 3⎤⎞ ⎡1 4 7⎤\n"
"\"transpose\"⎜⎢4 5 6⎥⎟ \"==\"⎢2 5 8⎥\n"
" ⎝⎣7 8 9⎦⎠ ⎣3 6 9⎦\n"
"```"
msgstr ""
"```bob\n"
" ⎛⎡1 2 3⎤⎞ ⎡1 4 7⎤\n"
"\"transpose\"⎜⎢4 5 6⎥⎟ \"==\"⎢2 5 8⎥\n"
" ⎝⎣7 8 9⎦⎠ ⎣3 6 9⎦\n"
"```"
#: src/exercises/day-1/for-loops.md:47
msgid "Hard-code both functions to operate on 3 × 3 matrices."
msgstr "두 함수 모두 행렬의 크기는 3 x 3 으로 하드코딩 합니다."
#: src/exercises/day-1/for-loops.md:49
msgid ""
"Copy the code below to <https://play.rust-lang.org/> and implement the "
"functions:"
msgstr ""
"아래 코드를 <https://play.rust-lang.org/>에 복사해서 구현하시면 됩니다:"
#: src/exercises/day-1/for-loops.md:52
msgid ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {\n"
" unimplemented!()\n"
"}\n"
"\n"
"fn pretty_print(matrix: &[[i32; 3]; 3]) {\n"
" unimplemented!()\n"
"}\n"
"\n"
"fn main() {\n"
" let matrix = [\n"
" [101, 102, 103], // <-- the comment makes rustfmt add a newline\n"
" [201, 202, 203],\n"
" [301, 302, 303],\n"
" ];\n"
"\n"
" println!(\"matrix:\");\n"
" pretty_print(&matrix);\n"
"\n"
" let transposed = transpose(matrix);\n"
" println!(\"transposed:\");\n"
" pretty_print(&transposed);\n"
"}\n"
"```"
msgstr ""
"```rust,should_panic\n"
"// TODO: 구현이 완료되면 아래 줄은 삭제합니다.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {\n"
" unimplemented!()\n"
"}\n"
"\n"
"fn pretty_print(matrix: &[[i32; 3]; 3]) {\n"
" unimplemented!()\n"
"}\n"
"\n"
"fn main() {\n"
" let matrix = [\n"
" [101, 102, 103], // <-- the comment makes rustfmt add a newline\n"
" [201, 202, 203],\n"
" [301, 302, 303],\n"
" ];\n"
"\n"
" println!(\"matrix:\");\n"
" pretty_print(&matrix);\n"
"\n"
" let transposed = transpose(matrix);\n"
" println!(\"transposed:\");\n"
" pretty_print(&transposed);\n"
"}\n"
"```"
#: src/exercises/day-1/for-loops.md:80
msgid "Bonus Question"
msgstr "보너스 문제"
#: src/exercises/day-1/for-loops.md:82
msgid ""
"Could you use `&[i32]` slices instead of hard-coded 3 × 3 matrices for your "
"argument and return types? Something like `&[&[i32]]` for a two-dimensional "
"slice-of-slices. Why or why not?"
msgstr ""
"`&[i32]`슬라이스를 잘 이용하면 행렬 크기를 3 x 3으로 하드코딩 하지 않을 수 있"
"을까요? 예컨데 `&[&[i32]]`는 2차원 슬라이스의 슬라이스 입니다. 가능하다면/하"
"지 않다면 왜 그런가요?"
#: src/exercises/day-1/for-loops.md:87
msgid ""
"See the [`ndarray` crate](https://docs.rs/ndarray/) for a production quality "
"implementation."
msgstr ""
"상용 품질의 구현에 대해서는 [`ndarray` 크레이트](https://docs.rs/ndarray/)를 "
"참조하시기 바랍니다."
#: src/exercises/day-1/for-loops.md:92
msgid ""
"The solution and the answer to the bonus section are available in the "
"[Solution](solutions-morning.md#arrays-and-for-loops) section."
msgstr ""
"보너스 문제에 대한 답변 역시 [해답](solutions-morning.md#arrays-and-for-"
"loops)에서 확인할 수 있습니다."
#: src/basic-syntax/variables.md:3
msgid ""
"Rust provides type safety via static typing. Variable bindings are immutable "
"by default:"
msgstr ""
"러스트는 정적 타이핑을 통해 타입 안전성을 제공합니다. 변수는 기본적으로 불변"
"(immutable)합니다:"
#: src/basic-syntax/variables.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let x: i32 = 10;\n"
" println!(\"x: {x}\");\n"
" // x = 20;\n"
" // println!(\"x: {x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let x: i32 = 10;\n"
" println!(\"x: {x}\");\n"
" // x = 20;\n"
" // println!(\"x: {x}\");\n"
"}\n"
"```"
#: src/basic-syntax/variables.md:17
msgid ""
"Due to type inference the `i32` is optional. We will gradually show the "
"types less and less as the course progresses."
msgstr ""
"타입 추론에 덕분에 `i32`는 생략 가능합니다. 강의가 진행될 수록 생략 가능한 부"
"분은 점점 생략할 것입니다."
#: src/basic-syntax/type-inference.md:3
msgid "Rust will look at how the variable is _used_ to determine the type:"
msgstr "러스트는 변수가 어떻게 사용되는지를 보고 그 변수의 타입을 추론합니다:"
#: src/basic-syntax/type-inference.md:5
msgid ""
"```rust,editable\n"
"fn takes_u32(x: u32) {\n"
" println!(\"u32: {x}\");\n"
"}\n"
"\n"
"fn takes_i8(y: i8) {\n"
" println!(\"i8: {y}\");\n"
"}\n"
"\n"
"fn main() {\n"
" let x = 10;\n"
" let y = 20;\n"
"\n"
" takes_u32(x);\n"
" takes_i8(y);\n"
" // takes_u32(y);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn takes_u32(x: u32) {\n"
" println!(\"u32: {x}\");\n"
"}\n"
"\n"
"fn takes_i8(y: i8) {\n"
" println!(\"i8: {y}\");\n"
"}\n"
"\n"
"fn main() {\n"
" let x = 10;\n"
" let y = 20;\n"
"\n"
" takes_u32(x);\n"
" takes_i8(y);\n"
" // takes_u32(y);\n"
"}\n"
"```"
#: src/basic-syntax/type-inference.md:26
msgid ""
"This slide demonstrates how the Rust compiler infers types based on "
"constraints given by variable declarations and usages."
msgstr ""
"이 슬라이드는, 러스트 컴파일러가 변수가 어떻게 선언되어 있고, 어떻게 사용되는"
"지를 제약 조건으로 삼아서 변수의 타입을 추론하는 모습을 보여줍니다."
#: src/basic-syntax/type-inference.md:28
msgid ""
"It is very important to emphasize that variables declared like this are not "
"of some sort of dynamic \"any type\" that can hold any data. The machine "
"code generated by such declaration is identical to the explicit declaration "
"of a type. The compiler does the job for us and helps us write more concise "
"code."
msgstr ""
"여기서 중요한 것은, 이렇게 명시적인 타입을 생략하고 선언되었다고 해서 \"어떤 "
"타입\"이라도 다 담을 수 있는 타입이 되는 것은 아니라는 점입니다. 명시적인 타"
"입 선언이 있던 없던, 컴파일러가 생성한 머신코드는 동일합니다. 컴파일러는 단"
"지 타입 선언을 생략할 수 있도록 해서 프로그래머가 더 간결한 코드를 쓸 수 있도"
"록 도와줄 뿐입니다."
#: src/basic-syntax/type-inference.md:32
msgid ""
"The following code tells the compiler to copy into a certain generic "
"container without the code ever explicitly specifying the contained type, "
"using `_` as a placeholder:"
msgstr ""
"아래 코드는, 제네릭 컨테이너를 쓸 때 컨테이터 안에 포함된 데이터의 타입을 명"
"시적으로 쓰지 않고 `_`로 대체하여도 된다는 것을 보여줍니다:"
#: src/basic-syntax/type-inference.md:34
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut v = Vec::new();\n"
" v.push((10, false));\n"
" v.push((20, true));\n"
" println!(\"v: {v:?}\");\n"
"\n"
" let vv = v.iter().collect::<std::collections::HashSet<_>>();\n"
" println!(\"vv: {vv:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut v = Vec::new();\n"
" v.push((10, false));\n"
" v.push((20, true));\n"
" println!(\"v: {v:?}\");\n"
"\n"
" let vv = v.iter().collect::<std::collections::HashSet<_>>();\n"
" println!(\"vv: {vv:?}\");\n"
"}\n"
"```"
#: src/basic-syntax/type-inference.md:46
msgid ""
"[`collect`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator."
"html#method.collect) relies on [`FromIterator`](https://doc.rust-lang.org/"
"std/iter/trait.FromIterator.html), which [`HashSet`](https://doc.rust-lang."
"org/std/collections/struct.HashSet.html#impl-FromIterator%3CT%3E-for-"
"HashSet%3CT,+S%3E) implements."
msgstr ""
"[`collect`](https://doc.rust-lang.org/stable/std/iter/trait.Iterator."
"html#method.collect)는 [`HashSet`](https://doc.rust-lang.org/std/collections/"
"struct.HashSet.html#impl-FromIterator%3CT%3E-for-HashSet%3CT,+S%3E)을 구현한 "
"[`FromIterator`](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)"
"에 의존합니다."
#: src/basic-syntax/static-and-const.md:1
msgid "Static and Constant Variables"
msgstr "정적변수(static)과 상수(const)"
#: src/basic-syntax/static-and-const.md:3
msgid ""
"Static and constant variables are two different ways to create globally-"
"scoped values that cannot be moved or reallocated during the execution of "
"the program. "
msgstr ""
"정적 변수와 상수는 전역 스코프에서 값을 생성하는 두 가지 방법입니다. 전역 스"
"코프에 생성된 값은 프로그램 수행 도중에 다른 값으로 이동되지 않으며, 메모리 "
"상에서 그 위치가 변하지 않습니다. "
#: src/basic-syntax/static-and-const.md:6
msgid "`const`"
msgstr "상수(`const`)"
#: src/basic-syntax/static-and-const.md:8
msgid ""
"Constant variables are evaluated at compile time and their values are "
"inlined wherever they are used:"
msgstr ""
"상수는 컴파일 할 때 그 값이 정해집니다. 그리고 그 값은 그 상수가 사용되는 모"
"든 부분에서 인라인 됩니다:"
#: src/basic-syntax/static-and-const.md:11
msgid ""
"```rust,editable\n"
"const DIGEST_SIZE: usize = 3;\n"
"const ZERO: Option<u8> = Some(42);\n"
"\n"
"fn compute_digest(text: &str) -> [u8; DIGEST_SIZE] {\n"
" let mut digest = [ZERO.unwrap_or(0); DIGEST_SIZE];\n"
" for (idx, &b) in text.as_bytes().iter().enumerate() {\n"
" digest[idx % DIGEST_SIZE] = digest[idx % DIGEST_SIZE]."
"wrapping_add(b);\n"
" }\n"
" digest\n"
"}\n"
"\n"
"fn main() {\n"
" let digest = compute_digest(\"Hello\");\n"
" println!(\"Digest: {digest:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"const DIGEST_SIZE: usize = 3;\n"
"const ZERO: Option<u8> = Some(42);\n"
"\n"
"fn compute_digest(text: &str) -> [u8; DIGEST_SIZE] {\n"
" let mut digest = [ZERO.unwrap_or(0); DIGEST_SIZE];\n"
" for (idx, &b) in text.as_bytes().iter().enumerate() {\n"
" digest[idx % DIGEST_SIZE] = digest[idx % DIGEST_SIZE]."
"wrapping_add(b);\n"
" }\n"
" digest\n"
"}\n"
"\n"
"fn main() {\n"
" let digest = compute_digest(\"Hello\");\n"
" println!(\"Digest: {digest:?}\");\n"
"}\n"
"```"
#: src/basic-syntax/static-and-const.md:29
msgid ""
"According to the [Rust RFC Book](https://rust-lang.github.io/rfcs/0246-const-"
"vs-static.html) these are inlined upon use."
msgstr ""
"[Rust RFC Book](https://rust-lang.github.io/rfcs/0246-const-vs-static.html)"
"에 따르면 상수는, 그 상수가 사용되는 곳에 인라인 됩니다."
#: src/basic-syntax/static-and-const.md:31
msgid ""
"Only functions marked `const` can be called at compile time to generate "
"`const` values. `const` functions can however be called at runtime."
msgstr ""
"`const` 값을 생성할 때에는 `const`로 마킹된 함수만이 호출 가능하며, 이 함수들"
"은 컴파일 시에 호출이 됩니다. 물론 `const`함수들을 런타임에 호출하는 것도 가"
"능합니다."
#: src/basic-syntax/static-and-const.md:33
msgid "`static`"
msgstr "정적변수(`static`)"
#: src/basic-syntax/static-and-const.md:35
msgid ""
"Static variables will live during the whole execution of the program, and "
"therefore will not move:"
msgstr ""
"정적 변수는 프로그램이 수행되는 동안 유지가 됩니다. 그러므로 다른 변수로 이동"
"(move)되지 않습니다:"
#: src/basic-syntax/static-and-const.md:37
msgid ""
"```rust,editable\n"
"static BANNER: &str = \"Welcome to RustOS 3.14\";\n"
"\n"
"fn main() {\n"
" println!(\"{BANNER}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"static BANNER: &str = \"Welcome to RustOS 3.14\";\n"
"\n"
"fn main() {\n"
" println!(\"{BANNER}\");\n"
"}\n"
"```"
#: src/basic-syntax/static-and-const.md:45
msgid ""
"As noted in the [Rust RFC Book](https://rust-lang.github.io/rfcs/0246-const-"
"vs-static.html), these are not inlined upon use and have an actual "
"associated memory location. This is useful for unsafe and embedded code, "
"and the variable lives through the entirety of the program execution. When a "
"globally-scoped value does not have a reason to need object identity, "
"`const` is generally preferred."
msgstr ""
"[Rust RFC Book](https://rust-lang.github.io/rfcs/0246-const-vs-static.html)에"
"서 언급한 바와 같이, 정적 변수는 별도의 메모리 공간을 가지며, 인라인 되지 않"
"습니다. 정적 변수는 안전하지 않은(unsafe) 러스트와 임베디드 시스템용 코드에"
"서 유용합니다. 이들의 수명은 프로그램이 수행되는 전체 시간과 동일합니다. 전"
"역 스코프를 가진 어떤 값이, 메모리 상에 단 하나만 존재해야 한다는 요구조건이 "
"없다면, 정적 변수 대신 `const`를 쓰는 것이 옳습니다."
#: src/basic-syntax/static-and-const.md:49
msgid ""
"Because `static` variables are accessible from any thread, they must be "
"`Sync`. Interior mutability is possible through a [`Mutex`](https://doc.rust-"
"lang.org/std/sync/struct.Mutex.html), atomic or similar. It is also possible "
"to have mutable statics, but they require manual synchronisation so any "
"access to them requires `unsafe` code. We will look at [mutable statics](../"
"unsafe/mutable-static-variables.md) in the chapter on Unsafe Rust."
msgstr ""
"`static`변수들은 어떤 스레드에서도 접근 가능하기 때문에, `Sync`트레잇을 구현"
"해야 합니다. 이 변수를 읽고 쓰려면 [`Mutex`](https://doc.rust-lang.org/std/"
"sync/struct.Mutex.html)로 감싸거나, atomic 연산을 써야 합니다. `static` 변수"
"를 mutable하게 선언할 수도 있지만, 이 경우 동기화 작업을 수동으로 해 주어야 "
"합니다. 그래서 그러한 변수를 접근하는 코드는`unsafe`로 명시적으로 표시가 되어"
"야 합니다. \"안전하지 않은 러스트\"를 배울 때 [mutable statics](../unsafe/"
"mutable-static-variables.md) 부분에서 좀 더 자세히 다루겠습니다."
#: src/basic-syntax/static-and-const.md:57
msgid "Mention that `const` behaves semantically similar to C++'s `constexpr`."
msgstr "러스트의 `const`는 C++의 `constexpr`과 매우 비슷합니다."
#: src/basic-syntax/static-and-const.md:58
msgid ""
"`static`, on the other hand, is much more similar to a `const` or mutable "
"global variable in C++."
msgstr ""
"반면에 러스트의 `static`은 C++의 `const`나 가변 정적 변수(mutable global "
"variable)와 훨씬 더 유사합니다."
#: src/basic-syntax/static-and-const.md:59
msgid ""
"`static` provides object identity: an address in memory and state as "
"required by types with interior mutability such as `Mutex<T>`."
msgstr ""
"`static`은 객체에 정체성을 부여합니다. 정체정이란 메모리 상에서의 주소, 그리"
"고 내부 상태를 의미합니다."
#: src/basic-syntax/static-and-const.md:60
msgid ""
"It isn't super common that one would need a runtime evaluated constant, but "
"it is helpful and safer than using a static."
msgstr ""
"프로그램 수행시 그 값이 정해지는 상수가 필요한 경우는 드뭅니다. 그러나 그렇다"
"고 해도, 정적 변수를 사용하는 것 보다는 더 유용하고 안전합니다."
#: src/basic-syntax/static-and-const.md:61
msgid "`thread_local` data can be created with the macro `std::thread_local`."
msgstr ""
"`thread_local` 데이터는 `std::thread_local` 매크로를 이용하여 생성할 수 있습"
"니다."
#: src/basic-syntax/static-and-const.md:63
msgid "Properties table:"
msgstr "속성 비교 테이블:"
#: src/basic-syntax/static-and-const.md:65
msgid "Property"
msgstr "속성"
#: src/basic-syntax/static-and-const.md:65
msgid "Static"
msgstr "정적(static) 변수"
#: src/basic-syntax/static-and-const.md:65
msgid "Constant"
msgstr "상수(constant)"
#: src/basic-syntax/static-and-const.md:67
msgid "Has an address in memory"
msgstr "메모리 상에 주소가 있는가"
#: src/basic-syntax/static-and-const.md:67
#: src/basic-syntax/static-and-const.md:68
#: src/basic-syntax/static-and-const.md:70
#: src/basic-syntax/static-and-const.md:71
msgid "Yes"
msgstr "예"
#: src/basic-syntax/static-and-const.md:67
msgid "No (inlined)"
msgstr "아니오(인라인 됨)"
#: src/basic-syntax/static-and-const.md:68
msgid "Lives for the entire duration of the program"
msgstr "프로그램이 수행되는 동안 계속 살아 있는가"
#: src/basic-syntax/static-and-const.md:68
#: src/basic-syntax/static-and-const.md:69
#: src/basic-syntax/static-and-const.md:71
msgid "No"
msgstr "아니오"
#: src/basic-syntax/static-and-const.md:69
msgid "Can be mutable"
msgstr "변경 가능한가"
#: src/basic-syntax/static-and-const.md:69
msgid "Yes (unsafe)"
msgstr "예 (그러나 안전하지 않음)"
#: src/basic-syntax/static-and-const.md:70
msgid "Evaluated at compile time"
msgstr "컴파일시 그 값이 결정되는가"
#: src/basic-syntax/static-and-const.md:70
msgid "Yes (initialised at compile time)"
msgstr "예 (컴파일시 초기화 됨)"
#: src/basic-syntax/static-and-const.md:71
msgid "Inlined wherever it is used"
msgstr "사용되는 곳에 인라인 되는가"
#: src/basic-syntax/scopes-shadowing.md:3
msgid ""
"You can shadow variables, both those from outer scopes and variables from "
"the same scope:"
msgstr ""
"현재 범위에 있는 변수와, 바깥 범위에 있는 변수 모두 가릴(쉐도잉)수 있습니다:"
#: src/basic-syntax/scopes-shadowing.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let a = 10;\n"
" println!(\"before: {a}\");\n"
"\n"
" {\n"
" let a = \"hello\";\n"
" println!(\"inner scope: {a}\");\n"
"\n"
" let a = true;\n"
" println!(\"shadowed in inner scope: {a}\");\n"
" }\n"
"\n"
" println!(\"after: {a}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let a = 10;\n"
" println!(\"before: {a}\");\n"
"\n"
" {\n"
" let a = \"hello\";\n"
" println!(\"inner scope: {a}\");\n"
"\n"
" let a = true;\n"
" println!(\"shadowed in inner scope: {a}\");\n"
" }\n"
"\n"
" println!(\"after: {a}\");\n"
"}\n"
"```"
#: src/basic-syntax/scopes-shadowing.md:25
msgid ""
"Definition: Shadowing is different from mutation, because after shadowing "
"both variable's memory locations exist at the same time. Both are available "
"under the same name, depending where you use it in the code. "
msgstr ""
"쉐도잉은 기존 변수에 새로운 값을 할당하는 것이 아닙니다. 쉐도잉을 하면 새로"
"운 변수가 생기며, 이전 변수와 새 변수는 메모리의 서로 다른 위치에 존재합니"
"다. 그 두 변수는 단지 이름이 같은 뿐이며, 코드 중 어디에서 그 이름이 사용되었"
"느냐에 따라 어떤 변수를 지칭하는 지가 결정됩니다. "
#: src/basic-syntax/scopes-shadowing.md:26
msgid "A shadowing variable can have a different type. "
msgstr "쉐도잉 시 타입을 바꿀 수 있습니다. "
#: src/basic-syntax/scopes-shadowing.md:27
msgid ""
"Shadowing looks obscure at first, but is convenient for holding on to values "
"after `.unwrap()`."
msgstr ""
"처음에 쉐도잉을 보면 코드를 더 모호하게 만든다고 생각할 수 도 있습니다. 그러"
"나 실제로 쉐도잉을 이용하면, 어떤 변수에서 `.unwrap()` 된 값을 새로운 변수에 "
"담을 경우 새로운 이름을 지을 필요 없이 기존 이름을 유지할 수 있어서 편리합니"
"다."
#: src/basic-syntax/scopes-shadowing.md:28
msgid ""
"The following code demonstrates why the compiler can't simply reuse memory "
"locations when shadowing an immutable variable in a scope, even if the type "
"does not change."
msgstr ""
"아래 코드는 불변 변수를 쉐도잉할 때 타입이 동일하더라도 새 변수가 원래 변수"
"의 메모리 위치를 재사용 할 수 없는지 그 이유를 보여줍니다."
#: src/basic-syntax/scopes-shadowing.md:30
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let a = 1;\n"
" let b = &a;\n"
" let a = a + 1;\n"
" println!(\"{a} {b}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let a = 1;\n"
" let b = &a;\n"
" let a = a + 1;\n"
" println!(\"{a} {b}\");\n"
"}\n"
"```"
#: src/memory-management.md:3
msgid "Traditionally, languages have fallen into two broad categories:"
msgstr "전통적으로, 두 종류의 프로그래밍 언어가 있습니다:"
#: src/memory-management.md:5
msgid "Full control via manual memory management: C, C++, Pascal, ..."
msgstr ""
"메모리 관리가 프로그래머의 완전한 통제하에 있지만 수동(그래서 안전하지 않을 "
"수 있는)인 언어: C, C++, Pascal, ..."
#: src/memory-management.md:6
msgid ""
"Full safety via automatic memory management at runtime: Java, Python, Go, "
"Haskell, ..."
msgstr ""
"메모리 관리가 런타임에 의해 되므로 안전하지만 자동(그래서 프로그래머가 개입"
"할 여지가 적거나 없는)인 언어: Java, Python, Go, Haskell, ..."
#: src/memory-management.md:8
msgid "Rust offers a new mix:"
msgstr "러스트는 이 둘을 혼합한 새로운 형태의 메모리 관리 기법을 제공합니다:"
#: src/memory-management.md:10
msgid ""
"Full control _and_ safety via compile time enforcement of correct memory "
"management."
msgstr ""
"컴파일 시 올바른 메모리 관리를 강제함으로써 완전한 통제와 안전성 _모두_ 제공."
#: src/memory-management.md:13
msgid "It does this with an explicit ownership concept."
msgstr "이를 가능하게 하는 러스트의 컨셉은 명시적인 소유권입니다."
#: src/memory-management.md:15
msgid "First, let's refresh how memory management works."
msgstr "우선 메모리 관리가 이뤄지는 방식을 다시 살펴 보겠습니다."
#: src/memory-management/stack-vs-heap.md:1
msgid "The Stack vs The Heap"
msgstr "스택(Stack)과 힙(Heap)"
#: src/memory-management/stack-vs-heap.md:3
msgid "Stack: Continuous area of memory for local variables."
msgstr "스택: 로컬 변수를 위한 연속적인 메모리 영역."
#: src/memory-management/stack-vs-heap.md:4
msgid "Values have fixed sizes known at compile time."
msgstr "여기 저장되는 값은 컴파일 시 결정되는 고정 크기를 갖습니다."
#: src/memory-management/stack-vs-heap.md:5
msgid "Extremely fast: just move a stack pointer."
msgstr ""
"매우 빠름: 메모리 할당/반환이 단지 스택 포인터의 이동만으로 구현됩니다."
#: src/memory-management/stack-vs-heap.md:6
msgid "Easy to manage: follows function calls."
msgstr "관리가 쉬움: 함수가 호출되면 할당되고, 리턴하면 반환됩니다."
#: src/memory-management/stack-vs-heap.md:7
msgid "Great memory locality."
msgstr "스택에 있는 값들은 매우 높은 메모리 인접성을 가집니다."
#: src/memory-management/stack-vs-heap.md:9
msgid "Heap: Storage of values outside of function calls."
msgstr "힙: 함수 호출/리턴과 상관 없이 유지되는 값이 저장되는 곳."
#: src/memory-management/stack-vs-heap.md:10
msgid "Values have dynamic sizes determined at runtime."
msgstr "여기 저장되는 값은 프로그램 수행시 그 크기가 결정됩니다."
#: src/memory-management/stack-vs-heap.md:11
msgid "Slightly slower than the stack: some book-keeping needed."
msgstr "스택 보다는 느림: 메모리 할당/반환시 해야 할 일이 좀 더 있습니다."
#: src/memory-management/stack-vs-heap.md:12
msgid "No guarantee of memory locality."
msgstr "메모리 인접성을 보장하지 않습니다."
#: src/memory-management/stack.md:1
msgid "Stack and Heap Example"
msgstr "스택과 힙에 관한 예제"
#: src/memory-management/stack.md:3
msgid ""
"Creating a `String` puts fixed-sized metadata on the stack and dynamically "
"sized data, the actual string, on the heap:"
msgstr ""
"`String`을 하나 만들게 되면, 스택에는 고정된 크기의 메타 데이터가 생성되고, "
"힙에는 가변 크기의 데이터, 즉, 실제 문자열, 이 생성됩니다:"
#: src/memory-management/stack.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let s1 = String::from(\"Hello\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let s1 = String::from(\"Hello\");\n"
"}\n"
"```"
#: src/memory-management/stack.md:12
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+----+----+ :\n"
": | ptr | o---+---+-----+-->| H | e | l | l | o | :\n"
": | len | 5 | : : +----+----+----+----+----+ :\n"
": | capacity | 5 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - - - - - -'\n"
"`- - - - - - - - - - - - - -'\n"
"```"
msgstr ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+----+----+ :\n"
": | ptr | o---+---+-----+-->| H | e | l | l | o | :\n"
": | len | 5 | : : +----+----+----+----+----+ :\n"
": | capacity | 5 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - - - - - -'\n"
"`- - - - - - - - - - - - - -'\n"
"```"
#: src/memory-management/stack.md:28
msgid ""
"Mention that a `String` is backed by a `Vec`, so it has a capacity and "
"length and can grow if mutable via reallocation on the heap."
msgstr ""
"문자열(`String`)은 실제로는 `Vec`입니다. 크기(capacity)와 현재 길이(length) "
"정보를 가지며, 더 큰 크기가 필요할 경우 힙에서 재 할당을 합니다."
#: src/memory-management/stack.md:30
msgid ""
"If students ask about it, you can mention that the underlying memory is heap "
"allocated using the [System Allocator](https://doc.rust-lang.org/std/alloc/"
"struct.System.html) and custom allocators can be implemented using the "
"[Allocator API](https://doc.rust-lang.org/std/alloc/index.html)"
msgstr ""
"힙은 기본적으로 [System Allocator](https://doc.rust-lang.org/std/alloc/"
"struct.System.html)를 통해 할당됩니다. 그리고 [Allocator API](https://doc."
"rust-lang.org/std/alloc/index.html)를 이용해서 커스텀 메모리 할당자를 만들 수"
"도 있습니다."
#: src/memory-management/stack.md:32
msgid ""
"We can inspect the memory layout with `unsafe` code. However, you should "
"point out that this is rightfully unsafe!"
msgstr ""
"아래와 같은 `unsafe` 코드로 메모리 레이아웃을 살펴볼 수 있습니다. 물론 이 코"
"드가 안전하지 않다는 점을 알려주세요!"
#: src/memory-management/stack.md:34
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut s1 = String::from(\"Hello\");\n"
" s1.push(' ');\n"
" s1.push_str(\"world\");\n"
" // DON'T DO THIS AT HOME! For educational purposes only.\n"
" // String provides no guarantees about its layout, so this could lead "
"to\n"
" // undefined behavior.\n"
" unsafe {\n"
" let (ptr, capacity, len): (usize, usize, usize) = std::mem::"
"transmute(s1);\n"
" println!(\"ptr = {ptr:#x}, len = {len}, capacity = {capacity}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut s1 = String::from(\"Hello\");\n"
" s1.push(' ');\n"
" s1.push_str(\"world\");\n"
" // DON'T DO THIS AT HOME! For educational purposes only.\n"
" // String provides no guarantees about its layout, so this could lead "
"to\n"
" // undefined behavior.\n"
" unsafe {\n"
" let (ptr, capacity, len): (usize, usize, usize) = std::mem::"
"transmute(s1);\n"
" println!(\"ptr = {ptr:#x}, len = {len}, capacity = {capacity}\");\n"
" }\n"
"}\n"
"\n"
"```"
#: src/memory-management/manual.md:3
msgid "You allocate and deallocate heap memory yourself."
msgstr "사용자가 직접 메모리를 할당, 해제 합니다."
#: src/memory-management/manual.md:5
msgid ""
"If not done with care, this can lead to crashes, bugs, security "
"vulnerabilities, and memory leaks."
msgstr ""
"조심하지 않으면, 충돌(crash), 버그, 보안취약성 및 메모리 누출이 발생할 수 있"
"습니다."
#: src/memory-management/manual.md:7
msgid "C Example"
msgstr "C 언어 예제"
#: src/memory-management/manual.md:9
msgid "You must call `free` on every pointer you allocate with `malloc`:"
msgstr "`malloc`으로 할당하는 포인터마다 `free`를 호출해야 합니다:"
#: src/memory-management/manual.md:11
msgid ""
"```c\n"
"void foo(size_t n) {\n"
" int* int_array = malloc(n * sizeof(int));\n"
" //\n"
" // ... lots of code\n"
" //\n"
" free(int_array);\n"
"}\n"
"```"
msgstr ""
"```c\n"
"void foo(size_t n) {\n"
" int* int_array = malloc(n * sizeof(int));\n"
" //\n"
" // ... lots of code\n"
" //\n"
" free(int_array);\n"
"}\n"
"```"
#: src/memory-management/manual.md:21
msgid ""
"Memory is leaked if the function returns early between `malloc` and `free`: "
"the pointer is lost and we cannot deallocate the memory. Worse, freeing the "
"pointer twice, or accessing a freed pointer can lead to exploitable security "
"vulnerabilities."
msgstr ""
"만약 `malloc` 과 `free` 사이에서 함수가 일찍 반환되면 메모리 누출이 일어납니"
"다: 포인터를 잃어버리게 되어 메모리를 반환할 수 없게 됩니다. 같은 포인터를 "
"두 번 반환하거나, 이미 반환된 포인터를 접근하는 것은 심각한 보안 문제를 일으"
"킬 수 있습니다."
#: src/memory-management/scope-based.md:3
msgid ""
"Constructors and destructors let you hook into the lifetime of an object."
msgstr ""
"생성자와 소멸자를 사용하여 객체의 생명주기에 따라 메모리 할당/해제가 일어나도"
"록 할 수 있습니다."
#: src/memory-management/scope-based.md:5
msgid ""
"By wrapping a pointer in an object, you can free memory when the object is "
"destroyed. The compiler guarantees that this happens, even if an exception "
"is raised."
msgstr ""
"포인터를 객체로 감싸도록 하면, 그 객체가 소멸될 때 그 포인터가 가리키는 메모"
"리가 해제되도록 할 수 있습니다. 컴파일러는 객체가 소멸될 때 반드시 소멸자가 "
"호출되는 것을 보장합니다. 심지어는 예외(exception)가 발생(_역주_: 함수의 리턴"
"이나 스코프의 종료 뿐만이 아니라) 하더라도요."
#: src/memory-management/scope-based.md:9
msgid ""
"This is often called _resource acquisition is initialization_ (RAII) and "
"gives you smart pointers."
msgstr ""
"이를 종종 RAII (Resource Acquisition Is Initialization)라고 하며, 이런 객체"
"는 일종의 스마트 포인터 역할을 합니다."
#: src/memory-management/scope-based.md:12
msgid "C++ Example"
msgstr "C++ 예제"
#: src/memory-management/scope-based.md:14
msgid ""
"```c++\n"
"void say_hello(std::unique_ptr<Person> person) {\n"
" std::cout << \"Hello \" << person->name << std::endl;\n"
"}\n"
"```"
msgstr ""
"```c++\n"
"void say_hello(std::unique_ptr<Person> person) {\n"
" std::cout << \"Hello \" << person->name << std::endl;\n"
"}\n"
"```"
#: src/memory-management/scope-based.md:20
msgid ""
"The `std::unique_ptr` object is allocated on the stack, and points to memory "
"allocated on the heap."
msgstr ""
"`std::unique_ptr`객체는 스택에 할당되며, 힙에 할당된 메모리를 가리킵니다."
#: src/memory-management/scope-based.md:22
msgid "At the end of `say_hello`, the `std::unique_ptr` destructor will run."
msgstr "`say_hello`함수가 끝나면 `std::unique_ptr`의 소멸자가 실행됩니다."
#: src/memory-management/scope-based.md:23
msgid "The destructor frees the `Person` object it points to."
msgstr "소멸자는 `Person` 객체가 가리키는 메모리를 해제합니다."
#: src/memory-management/scope-based.md:25
msgid ""
"Special move constructors are used when passing ownership to a function:"
msgstr "이동 생성자는 함수 호출 시 소유권을 전달할때 사용됩니다:"
#: src/memory-management/scope-based.md:27
msgid ""
"```c++\n"
"std::unique_ptr<Person> person = find_person(\"Carla\");\n"
"say_hello(std::move(person));\n"
"```"
msgstr ""
"```c++\n"
"std::unique_ptr<Person> person = find_person(\"Carla\");\n"
"say_hello(std::move(person));\n"
"```"
#: src/memory-management/garbage-collection.md:1
msgid "Automatic Memory Management"
msgstr "자동 메모리 관리"
#: src/memory-management/garbage-collection.md:3
msgid ""
"An alternative to manual and scope-based memory management is automatic "
"memory management:"
msgstr ""
"수동, 스코프기반 메모리 관리의 대안으로 자동 메모리 관리 방식이 있습니다:"
#: src/memory-management/garbage-collection.md:6
msgid "The programmer never allocates or deallocates memory explicitly."
msgstr "개발자는 메모리를 명시적으로 할당/해제 하지 않습니다."
#: src/memory-management/garbage-collection.md:7
msgid ""
"A garbage collector finds unused memory and deallocates it for the "
"programmer."
msgstr "가비지 컬렉터(GC)는 사용되지 않는 메모리를 찾아 해제합니다."
#: src/memory-management/garbage-collection.md:9
msgid "Java Example"
msgstr "Java 예제"
#: src/memory-management/garbage-collection.md:11
msgid "The `person` object is not deallocated after `sayHello` returns:"
msgstr ""
"`person`객체는 `sayHello`함수 반환 후에도 해제되지 않습니다. (_역주_: GC가 나"
"중에 알아서 해제합니다.)"
#: src/memory-management/garbage-collection.md:13
msgid ""
"```java\n"
"void sayHello(Person person) {\n"
" System.out.println(\"Hello \" + person.getName());\n"
"}\n"
"```"
msgstr ""
"```java\n"
"void sayHello(Person person) {\n"
" System.out.println(\"Hello \" + person.getName());\n"
"}\n"
"```"
#: src/memory-management/rust.md:1
msgid "Memory Management in Rust"
msgstr "러스트에서의 메모리 관리"
#: src/memory-management/rust.md:3
msgid "Memory management in Rust is a mix:"
msgstr "러스트의 메모리 관리는 지금까지 설명한 방식들을 혼합해서 사용합니다:"
#: src/memory-management/rust.md:5
msgid "Safe and correct like Java, but without a garbage collector."
msgstr "자바처럼 안전하고 정확합니다. 하지만 GC는 없습니다."
#: src/memory-management/rust.md:6
msgid ""
"Depending on which abstraction (or combination of abstractions) you choose, "
"can be a single unique pointer, reference counted, or atomically reference "
"counted."
msgstr ""
"다양한 추상화를 제공합니다: 단일 포인터, 참조 카운트, 아토믹(atomic) 참조 카"
"운트."
#: src/memory-management/rust.md:7
msgid "Scope-based like C++, but the compiler enforces full adherence."
msgstr ""
"C++ 처럼 범위(스코프) 기반입니다. 하지만 컴파일러가 훨씬 더 엄격합니다."
#: src/memory-management/rust.md:8
msgid ""
"A Rust user can choose the right abstraction for the situation, some even "
"have no cost at runtime like C."
msgstr ""
"사용자는 상황에 따라 적합한 추상화를 선택할 수 있습니다. 그 중에는 C 언어 처"
"럼 런타임 오버헤드가 없는 것도 있습니다."
#: src/memory-management/rust.md:10
msgid "Rust achieves this by modeling _ownership_ explicitly."
msgstr ""
"러스트는 \\_소유권_을 언어 차원에서 명시적으로 모델링 함으로써 이를 이룹니다."
#: src/memory-management/rust.md:14
msgid ""
"If asked how at this point, you can mention that in Rust this is usually "
"handled by RAII wrapper types such as [Box](https://doc.rust-lang.org/std/"
"boxed/struct.Box.html), [Vec](https://doc.rust-lang.org/std/vec/struct.Vec."
"html), [Rc](https://doc.rust-lang.org/std/rc/struct.Rc.html), or [Arc]"
"(https://doc.rust-lang.org/std/sync/struct.Arc.html). These encapsulate "
"ownership and memory allocation via various means, and prevent the potential "
"errors in C."
msgstr ""
"이 시점에서 그게 어떻게 가능하냐는 질문이 있으면, 러스트에서 이 작업은 일반적"
"으로 [Box](https://doc.rust-lang.org/std/boxed/struct.Box.html), [Vec]"
"(https://doc.rust-lang.org/std/vec/struct.Vec.html), [Rc](https://doc.rust-"
"lang.org/std/rc/struct.Rc.html) 또는 [Arc](https://doc.rust-lang.org/std/"
"sync/struct.Arc.html)와 같은 RAII 타입에 의해 처리된다고 답변할 수 있습니다. "
"이들은 다양한 방법을 통해 소유권과 메모리 할당에 대한 구체적인 내용을을 캡슐"
"화하여, C 언어였다면 발생할 수 있었을 다양한 에러를 막습니다."
#: src/memory-management/rust.md:16
msgid ""
"You may be asked about destructors here, the [Drop](https://doc.rust-lang."
"org/std/ops/trait.Drop.html) trait is the Rust equivalent."
msgstr ""
"소멸자에 대한 질문도 있을 수 있습니다. [Drop](https://doc.rust-lang.org/std/"
"ops/trait.Drop.html) 트레잇이 답입니다."
#: src/memory-management/comparison.md:3
msgid "Here is a rough comparison of the memory management techniques."
msgstr "메모리 관리 기술의 대략적인 비교입니다."
#: src/memory-management/comparison.md:5
msgid "Pros of Different Memory Management Techniques"
msgstr "메모리 관리 방법 별 장점"
#: src/memory-management/comparison.md:7 src/memory-management/comparison.md:22
msgid "Manual like C:"
msgstr "C와 같은 수동 관리:"
#: src/memory-management/comparison.md:8 src/memory-management/comparison.md:14
#: src/memory-management/comparison.md:17
msgid "No runtime overhead."
msgstr "런타임 오버헤드가 없음."
#: src/memory-management/comparison.md:9 src/memory-management/comparison.md:26
msgid "Automatic like Java:"
msgstr "JAVA와 같은 자동화 관리:"
#: src/memory-management/comparison.md:10
msgid "Fully automatic."
msgstr "완전한 자동화."
#: src/memory-management/comparison.md:11
#: src/memory-management/comparison.md:18
msgid "Safe and correct."
msgstr "안전하고 정확함."
#: src/memory-management/comparison.md:12
#: src/memory-management/comparison.md:29
msgid "Scope-based like C++:"
msgstr "C++ 와 같은 범위 기반 관리:"
#: src/memory-management/comparison.md:13
msgid "Partially automatic."
msgstr "부분 자동화."
#: src/memory-management/comparison.md:15
msgid "Compiler-enforced scope-based like Rust:"
msgstr "러스트와 같은 컴파일러 수행 범위 기반 관리:"
#: src/memory-management/comparison.md:16
msgid "Enforced by compiler."
msgstr "컴파일러에 의해 수행됩니다."
#: src/memory-management/comparison.md:20
msgid "Cons of Different Memory Management Techniques"
msgstr "메모리 관리 방법 별 단점"
#: src/memory-management/comparison.md:23
msgid "Use-after-free."
msgstr "사용 후 해제 문제."
#: src/memory-management/comparison.md:24
msgid "Double-frees."
msgstr "이중 해제 문제."
#: src/memory-management/comparison.md:25
msgid "Memory leaks."
msgstr "메모리 누출 문제."
#: src/memory-management/comparison.md:27
msgid "Garbage collection pauses."
msgstr "GC동작으로 인한 멈춤."
#: src/memory-management/comparison.md:28
msgid "Destructor delays."
msgstr ""
"소멸자 지연 (_역주_: 특정 메모리를 더이상 사용하지 않더라도 곧바로 해제 되지 "
"않고 GC가 동작할 때 까지 기다려야 한다는 점)"
#: src/memory-management/comparison.md:30
msgid "Complex, opt-in by programmer (on C++)."
msgstr "복잡하며, 개발자의 선택사항임."
#: src/memory-management/comparison.md:31
msgid "Circular references can lead to memory leaks"
msgstr "순환 참조가 발생하면 메모리 누수가 발생함"
#: src/memory-management/comparison.md:32
msgid "Potential runtime overhead"
msgstr "런타임 오버헤드 있을 수 있음"
#: src/memory-management/comparison.md:33
msgid "Compiler-enforced and scope-based like Rust:"
msgstr "러스트와 같은 컴파일러가 강제하는 수행 범위 기반 관리:"
#: src/memory-management/comparison.md:34
msgid "Some upfront complexity."
msgstr "처음에 배울 때 어려움."
#: src/memory-management/comparison.md:35
msgid "Can reject valid programs."
msgstr "올바른 프로그램이더라도 컴파일러가 거부할 수 있음."
#: src/ownership.md:3
msgid ""
"All variable bindings have a _scope_ where they are valid and it is an error "
"to use a variable outside its scope:"
msgstr ""
"모든 변수 바인딩은 유효한 \"범위(스코프)\"를 가지며, 범위 밖에서 변수 사용하"
"면 에러가 발생합니다:"
#: src/ownership.md:6
msgid ""
"```rust,editable,compile_fail\n"
"struct Point(i32, i32);\n"
"\n"
"fn main() {\n"
" {\n"
" let p = Point(3, 4);\n"
" println!(\"x: {}\", p.0);\n"
" }\n"
" println!(\"y: {}\", p.1);\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"struct Point(i32, i32);\n"
"\n"
"fn main() {\n"
" {\n"
" let p = Point(3, 4);\n"
" println!(\"x: {}\", p.0);\n"
" }\n"
" println!(\"y: {}\", p.1);\n"
"}\n"
"```"
#: src/ownership.md:18
msgid ""
"At the end of the scope, the variable is _dropped_ and the data is freed."
msgstr ""
"스코프가 종료되면 변수는 \"삭제(drop)\"되었다고 하며 그 변수의 데이터는 메모"
"리에서 해제됩니다."
#: src/ownership.md:19
msgid "A destructor can run here to free up resources."
msgstr ""
"스코프가 종료될 때 다른 리소스를 해제하기 위해 소멸자가 호출되도록 할 수 있습"
"니다."
#: src/ownership.md:20
msgid "We say that the variable _owns_ the value."
msgstr "이것을 두고 변수가 값을 \"소유\"한다고 표현합니다."
#: src/ownership/move-semantics.md:3
msgid "An assignment will transfer _ownership_ between variables:"
msgstr "(변수의) 할당은 \\_소유권_을 변수 간에 이동시킵니다:"
#: src/ownership/move-semantics.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let s1: String = String::from(\"Hello!\");\n"
" let s2: String = s1;\n"
" println!(\"s2: {s2}\");\n"
" // println!(\"s1: {s1}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let s1: String = String::from(\"Hello!\");\n"
" let s2: String = s1;\n"
" println!(\"s2: {s2}\");\n"
" // println!(\"s1: {s1}\");\n"
"}\n"
"```"
#: src/ownership/move-semantics.md:14
msgid "The assignment of `s1` to `s2` transfers ownership."
msgstr "`s1`을 `s2`에 할당하여 소유권을 이전시킵니다."
#: src/ownership/move-semantics.md:15
msgid "When `s1` goes out of scope, nothing happens: it does not own anything."
msgstr ""
"`s1`의 스코프가 종료되면 아무 일도 없습니다: 왜냐하면 `s1`은 아무런 소유권이 "
"없기 때문입니다."
#: src/ownership/move-semantics.md:16
msgid "When `s2` goes out of scope, the string data is freed."
msgstr "`s2`의 스코프가 종료되면 문자열 데이터는 해제됩니다."
#: src/ownership/move-semantics.md:17
msgid "There is always _exactly_ one variable binding which owns a value."
msgstr "값(데이터)의 소유권을 갖는 변수는 항상 _단_ 하나 입니다."
#: src/ownership/move-semantics.md:21
msgid ""
"Mention that this is the opposite of the defaults in C++, which copies by "
"value unless you use `std::move` (and the move constructor is defined!)."
msgstr ""
"이는 C++과 정반대 임을 설명하세요. C++에서는 복사가 기본이고, `std::move` 를 "
"이용해야만 (그리고 이동 생성자가 정의되어 있어야만!) 소유권 이전이 됩니다."
#: src/ownership/move-semantics.md:23
msgid ""
"It is only the ownership that moves. Whether any machine code is generated "
"to manipulate the data itself is a matter of optimization, and such copies "
"are aggressively optimized away."
msgstr ""
"실제로 이동되는 것은 소유권일 뿐입니다. 머신 코드 레벨에서 데이터 복사가 일어"
"날 지 말 지에 대한 것은 컴파일러 내부에서 일어나는 최적화 문제입니다. 이런 복"
"사는 최적화 과정에서 제거가 됩니다."
#: src/ownership/move-semantics.md:25
msgid ""
"Simple values (such as integers) can be marked `Copy` (see later slides)."
msgstr ""
"정수와 같은 간단한 값들은 `Copy` (뒤에 설명합니다)로 마킹될 수 있습니다."
#: src/ownership/move-semantics.md:27
msgid "In Rust, clones are explicit (by using `clone`)."
msgstr "러스트에서는 복사할때에는 명시적으로 `clone`을 사용합니다."
#: src/ownership/moved-strings-rust.md:3
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let s1: String = String::from(\"Rust\");\n"
" let s2: String = s1;\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let s1: String = String::from(\"Rust\");\n"
" let s2: String = s1;\n"
"}\n"
"```"
#: src/ownership/moved-strings-rust.md:10
msgid "The heap data from `s1` is reused for `s2`."
msgstr "`s1`의 힙 데이터는 `s2`에서 재사용 됩니다."
#: src/ownership/moved-strings-rust.md:11
msgid "When `s1` goes out of scope, nothing happens (it has been moved from)."
msgstr ""
"`s1`의 스코프가 종료되면 아무일도 일어나지 않습니다.(이미 이동되었습니다.)"
#: src/ownership/moved-strings-rust.md:13
msgid "Before move to `s2`:"
msgstr "`s2`로 이동 전 메모리:"
#: src/ownership/moved-strings-rust.md:15
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+----+ :\n"
": | ptr | o---+---+-----+-->| R | u | s | t | :\n"
": | len | 4 | : : +----+----+----+----+ :\n"
": | capacity | 4 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - - - -'\n"
": :\n"
"`- - - - - - - - - - - - - -'\n"
"```"
msgstr ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+----+ :\n"
": | ptr | o---+---+-----+-->| R | u | s | t | :\n"
": | len | 4 | : : +----+----+----+----+ :\n"
": | capacity | 4 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - - - -'\n"
": :\n"
"`- - - - - - - - - - - - - -'\n"
"```"
#: src/ownership/moved-strings-rust.md:30
msgid "After move to `s2`:"
msgstr "`s2`로 이동 후 메모리:"
#: src/ownership/moved-strings-rust.md:32
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - -.\n"
": : : :\n"
": s1 \"(inaccessible)\" : : :\n"
": +-----------+-------+ : : +----+----+----+----+ :\n"
": | ptr | o---+---+--+--+-->| R | u | s | t | :\n"
": | len | 4 | : | : +----+----+----+----+ :\n"
": | capacity | 4 | : | : :\n"
": +-----------+-------+ : | : :\n"
": : | `- - - - - - - - - - - - - -'\n"
": s2 : |\n"
": +-----------+-------+ : |\n"
": | ptr | o---+---+--'\n"
": | len | 4 | :\n"
": | capacity | 4 | :\n"
": +-----------+-------+ :\n"
": :\n"
"`- - - - - - - - - - - - - -'\n"
"```"
msgstr ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - -.\n"
": : : :\n"
": s1 \"(inaccessible)\" : : :\n"
": +-----------+-------+ : : +----+----+----+----+ :\n"
": | ptr | o---+---+--+--+-->| R | u | s | t | :\n"
": | len | 4 | : | : +----+----+----+----+ :\n"
": | capacity | 4 | : | : :\n"
": +-----------+-------+ : | : :\n"
": : | `- - - - - - - - - - - - - -'\n"
": s2 : |\n"
": +-----------+-------+ : |\n"
": | ptr | o---+---+--'\n"
": | len | 4 | :\n"
": | capacity | 4 | :\n"
": +-----------+-------+ :\n"
": :\n"
"`- - - - - - - - - - - - - -'\n"
"```"
#: src/ownership/double-free-modern-cpp.md:1
msgid "Extra Work in Modern C++"
msgstr "Modern C++에서 이중해제 문제"
#: src/ownership/double-free-modern-cpp.md:3
msgid "Modern C++ solves this differently:"
msgstr "Modern C++은 이 문제를 다르게 해결합니다:"
#: src/ownership/double-free-modern-cpp.md:5
msgid ""
"```c++\n"
"std::string s1 = \"Cpp\";\n"
"std::string s2 = s1; // Duplicate the data in s1.\n"
"```"
msgstr ""
"```c++\n"
"std::string s1 = \"Cpp\";\n"
"std::string s2 = s1; // s1의 데이터를 복제합니다.\n"
"```"
#: src/ownership/double-free-modern-cpp.md:10
msgid ""
"The heap data from `s1` is duplicated and `s2` gets its own independent copy."
msgstr "`s1`의 힙 데이터는 복제되고, `s2`는 독립적인 복사본을 얻습니다."
#: src/ownership/double-free-modern-cpp.md:11
msgid "When `s1` and `s2` go out of scope, they each free their own memory."
msgstr "`s1` 와 `s2`의 스코프가 종료되면 각각의 메모리가 해제됩니다."
#: src/ownership/double-free-modern-cpp.md:13
msgid "Before copy-assignment:"
msgstr "복사 전:"
#: src/ownership/double-free-modern-cpp.md:16
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+ :\n"
": | ptr | o---+---+--+--+-->| C | p | p | :\n"
": | len | 3 | : : +----+----+----+ :\n"
": | capacity | 3 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - -'\n"
"`- - - - - - - - - - - - - -'\n"
"```"
msgstr ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+ :\n"
": | ptr | o---+---+--+--+-->| C | p | p | :\n"
": | len | 3 | : : +----+----+----+ :\n"
": | capacity | 3 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - -'\n"
"`- - - - - - - - - - - - - -'\n"
"```"
#: src/ownership/double-free-modern-cpp.md:30
msgid "After copy-assignment:"
msgstr "복사 후:"
#: src/ownership/double-free-modern-cpp.md:32
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+ :\n"
": | ptr | o---+---+--+--+-->| C | p | p | :\n"
": | len | 3 | : : +----+----+----+ :\n"
": | capacity | 3 | : : :\n"
": +-----------+-------+ : : :\n"
": : : :\n"
": s2 : : :\n"
": +-----------+-------+ : : +----+----+----+ :\n"
": | ptr | o---+---+-----+-->| C | p | p | :\n"
": | len | 3 | : : +----+----+----+ :\n"
": | capacity | 3 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - -'\n"
"`- - - - - - - - - - - - - -'\n"
"```"
msgstr ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - -.\n"
": : : :\n"
": s1 : : :\n"
": +-----------+-------+ : : +----+----+----+ :\n"
": | ptr | o---+---+--+--+-->| C | p | p | :\n"
": | len | 3 | : : +----+----+----+ :\n"
": | capacity | 3 | : : :\n"
": +-----------+-------+ : : :\n"
": : : :\n"
": s2 : : :\n"
": +-----------+-------+ : : +----+----+----+ :\n"
": | ptr | o---+---+-----+-->| C | p | p | :\n"
": | len | 3 | : : +----+----+----+ :\n"
": | capacity | 3 | : : :\n"
": +-----------+-------+ : : :\n"
": : `- - - - - - - - - - - -'\n"
"`- - - - - - - - - - - - - -'\n"
"```"
#: src/ownership/moves-function-calls.md:3
msgid ""
"When you pass a value to a function, the value is assigned to the function "
"parameter. This transfers ownership:"
msgstr ""
"값을 함수에 전달할때, 그 값은 매개변수에 할당됩니다. 이때 소유권의 이동이 일"
"어납니다:"
#: src/ownership/moves-function-calls.md:6
msgid ""
"```rust,editable\n"
"fn say_hello(name: String) {\n"
" println!(\"Hello {name}\")\n"
"}\n"
"\n"
"fn main() {\n"
" let name = String::from(\"Alice\");\n"
" say_hello(name);\n"
" // say_hello(name);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn say_hello(name: String) {\n"
" println!(\"Hello {name}\")\n"
"}\n"
"\n"
"fn main() {\n"
" let name = String::from(\"Alice\");\n"
" say_hello(name);\n"
" // say_hello(name);\n"
"}\n"
"```"
#: src/ownership/moves-function-calls.md:20
msgid ""
"With the first call to `say_hello`, `main` gives up ownership of `name`. "
"Afterwards, `name` cannot be used anymore within `main`."
msgstr ""
"`say_hello`함수의 첫번째 호출시 `main`함수는 자신이 가진 `name`에 대한 소유권"
"을 포기하므로, 이후 `main`함수에서는 `name`을 사용할 수 없습니다."
#: src/ownership/moves-function-calls.md:21
msgid ""
"The heap memory allocated for `name` will be freed at the end of the "
"`say_hello` function."
msgstr "`name`에 할당되있는 힙 메모리는 `say_hello`함수의 끝에서 해제됩니다."
#: src/ownership/moves-function-calls.md:22
msgid ""
"`main` can retain ownership if it passes `name` as a reference (`&name`) and "
"if `say_hello` accepts a reference as a parameter."
msgstr ""
"`main`함수에서 `name`을 참조로 전달(빌림)하고(`&name`), `say_hello`에서 매개"
"변수를 참조형으로 수정한다면 `main`함수는 `name`의 소유권을 유지할 수 있습니"
"다."
#: src/ownership/moves-function-calls.md:23
msgid ""
"Alternatively, `main` can pass a clone of `name` in the first call (`name."
"clone()`)."
msgstr ""
"또는 첫번째 호출 시 `main`함수에서 `name`을 복제하여 전달할 수도 있습니다."
"(`name.clone()`)"
#: src/ownership/moves-function-calls.md:24
msgid ""
"Rust makes it harder than C++ to inadvertently create copies by making move "
"semantics the default, and by forcing programmers to make clones explicit."
msgstr ""
"러스트는 이동을 기본으로 하고 복제를 명시적으로 선언하도록 만듬으로, 의도치 "
"않게 복사본을 만드는 것이 C++에서보다 어렵습니다."
#: src/ownership/copy-clone.md:3
msgid ""
"While move semantics are the default, certain types are copied by default:"
msgstr "이동이 기본 설정이지만, 특정 타입은 복사됩니다:"
#: src/ownership/copy-clone.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let x = 42;\n"
" let y = x;\n"
" println!(\"x: {x}\");\n"
" println!(\"y: {y}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let x = 42;\n"
" let y = x;\n"
" println!(\"x: {x}\");\n"
" println!(\"y: {y}\");\n"
"}\n"
"```"
#: src/ownership/copy-clone.md:14
msgid "These types implement the `Copy` trait."
msgstr "이러한 타입들은 `Copy` 트레잇을 구현합니다."
#: src/ownership/copy-clone.md:16
msgid "You can opt-in your own types to use copy semantics:"
msgstr "직접 만든 타입들도 `Copy`트레잇을 구현하여 복사를 할 수 있습니다:"
#: src/ownership/copy-clone.md:18
msgid ""
"```rust,editable\n"
"#[derive(Copy, Clone, Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn main() {\n"
" let p1 = Point(3, 4);\n"
" let p2 = p1;\n"
" println!(\"p1: {p1:?}\");\n"
" println!(\"p2: {p2:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Copy, Clone, Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn main() {\n"
" let p1 = Point(3, 4);\n"
" let p2 = p1;\n"
" println!(\"p1: {p1:?}\");\n"
" println!(\"p2: {p2:?}\");\n"
"}\n"
"```"
#: src/ownership/copy-clone.md:30
msgid "After the assignment, both `p1` and `p2` own their own data."
msgstr "할당 후, `p1`와 `p2`는 자신의 데이터를 소유합니다."
#: src/ownership/copy-clone.md:31
msgid "We can also use `p1.clone()` to explicitly copy the data."
msgstr "명시적으로 `p1.clone()`를 사용하여 데이터를 복사할 수 있습니다."
#: src/ownership/copy-clone.md:35
msgid "Copying and cloning are not the same thing:"
msgstr "복사(copy)와 복제(clone)는 같지 않습니다:"
#: src/ownership/copy-clone.md:37
msgid ""
"Copying refers to bitwise copies of memory regions and does not work on "
"arbitrary objects."
msgstr ""
"복사는 메모리의 내용을 그대로 한 벌 더 만드는 것을 의미하며, 아무 객체에서나 "
"다 지원하지는 않습니다."
#: src/ownership/copy-clone.md:38
msgid ""
"Copying does not allow for custom logic (unlike copy constructors in C++)."
msgstr ""
"복사는 커스터마이즈 할 수 없습니다. (C++에서 복사 생성자를 통해 복사 동작을 "
"임의로 구현할 수 있는 것과 비교가 됩니다.)"
#: src/ownership/copy-clone.md:39
msgid ""
"Cloning is a more general operation and also allows for custom behavior by "
"implementing the `Clone` trait."
msgstr ""
"복제는 보다 일반적인 작업이며, `Clone`트레잇을 구현하여 복제시 동작을 커스터"
"마이즈 할 수 있습니다."
#: src/ownership/copy-clone.md:40
msgid "Copying does not work on types that implement the `Drop` trait."
msgstr "`Drop` 트레잇을 구현한 타입은 복사되지 않습니다."
#: src/ownership/copy-clone.md:42 src/ownership/lifetimes-function-calls.md:29
msgid "In the above example, try the following:"
msgstr "위의 예시에서 다음을 시도해 보시기 바랍니다:"
#: src/ownership/copy-clone.md:44
msgid ""
"Add a `String` field to `struct Point`. It will not compile because `String` "
"is not a `Copy` type."
msgstr ""
"`Point`구조체에 `String`필드를 추가하세요. 컴파일 되지 않을 것입니다. 왜냐하"
"면 `String`은 `Copy`트레잇을 구현하고 있지 않기 때문입니다."
#: src/ownership/copy-clone.md:45
msgid ""
"Remove `Copy` from the `derive` attribute. The compiler error is now in the "
"`println!` for `p1`."
msgstr ""
"`derive` 속성에서 `Copy`를 제거해 보세요. `p1`을 `println!` 할 때 컴파일 에러"
"가 발생할 것입니다."
#: src/ownership/copy-clone.md:46
msgid "Show that it works if you clone `p1` instead."
msgstr "`p1`을 복제하면 잘 동작함을 확인해 보세요."
#: src/ownership/copy-clone.md:48
msgid ""
"If students ask about `derive`, it is sufficient to say that this is a way "
"to generate code in Rust at compile time. In this case the default "
"implementations of `Copy` and `Clone` traits are generated."
msgstr ""
"만약 학생들이 `derive`에 대해 묻는다면, 컴파일 시 러스트에서 코드를 생성하는"
"방법이라고 말하는 것으로 충분합니다. 위 경우 `Copy`와 `Clone` 트레잇에 대한 "
"기본 구현이 생성됩니다."
#: src/ownership/borrowing.md:3
msgid ""
"Instead of transferring ownership when calling a function, you can let a "
"function _borrow_ the value:"
msgstr ""
"함수 호출시 값의 소유권을 이동하는 대신의 함수가 값을 _빌려올 수_ 있습니다:"
#: src/ownership/borrowing.md:6
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn add(p1: &Point, p2: &Point) -> Point {\n"
" Point(p1.0 + p2.0, p1.1 + p2.1)\n"
"}\n"
"\n"
"fn main() {\n"
" let p1 = Point(3, 4);\n"
" let p2 = Point(10, 20);\n"
" let p3 = add(&p1, &p2);\n"
" println!(\"{p1:?} + {p2:?} = {p3:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn add(p1: &Point, p2: &Point) -> Point {\n"
" Point(p1.0 + p2.0, p1.1 + p2.1)\n"
"}\n"
"\n"
"fn main() {\n"
" let p1 = Point(3, 4);\n"
" let p2 = Point(10, 20);\n"
" let p3 = add(&p1, &p2);\n"
" println!(\"{p1:?} + {p2:?} = {p3:?}\");\n"
"}\n"
"```"
#: src/ownership/borrowing.md:22
msgid "The `add` function _borrows_ two points and returns a new point."
msgstr ""
"`add` 함수는 두 `Point` 객체 값을 \\_빌려_와서 새로운 `Point` 객체를 반환합니"
"다."
#: src/ownership/borrowing.md:23
msgid "The caller retains ownership of the inputs."
msgstr "`p1`과 `p2`의 소유권은 여전히 호출자(`main`함수)에 있습니다."
#: src/ownership/borrowing.md:27
msgid "Notes on stack returns:"
msgstr "스택에 할당된 값을 리턴하는 것에 대한 참고:"
#: src/ownership/borrowing.md:28
msgid ""
"Demonstrate that the return from `add` is cheap because the compiler can "
"eliminate the copy operation. Change the above code to print stack addresses "
"and run it on the [Playground](https://play.rust-lang.org/) or look at the "
"assembly in [Godbolt](https://rust.godbolt.org/). In the \"DEBUG\" "
"optimization level, the addresses should change, while they stay the same "
"when changing to the \"RELEASE\" setting:"
msgstr ""
"`add`에서 값을 반환하는 것은 매우 값이 싸다는 것을 설명하세요. 왜냐하면, 컴파"
"일러가 복사 과정을 생략할 수 있기 때문입니다. 위 코드를 스택 주소를 출력하도"
"록 수정하고 [Playground](https://play.rust-lang.org/)에서 수행해 보세요. 또"
"는 [Godbolt](https://rust.godbolt.org/)에서 어셈블리를 확인해 보세요. 최적화 "
"레벨이 \"DEBUG\" 일 때에는 주소가 바뀌지만, \"RELEASE\" 레벨에서는 바뀌지 않"
"습니다:"
#: src/ownership/borrowing.md:30
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn add(p1: &Point, p2: &Point) -> Point {\n"
" let p = Point(p1.0 + p2.0, p1.1 + p2.1);\n"
" println!(\"&p.0: {:p}\", &p.0);\n"
" p\n"
"}\n"
"\n"
"pub fn main() {\n"
" let p1 = Point(3, 4);\n"
" let p2 = Point(10, 20);\n"
" let p3 = add(&p1, &p2);\n"
" println!(\"&p3.0: {:p}\", &p3.0);\n"
" println!(\"{p1:?} + {p2:?} = {p3:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn add(p1: &Point, p2: &Point) -> Point {\n"
" let p = Point(p1.0 + p2.0, p1.1 + p2.1);\n"
" println!(\"&p.0: {:p}\", &p.0);\n"
" p\n"
"}\n"
"\n"
"pub fn main() {\n"
" let p1 = Point(3, 4);\n"
" let p2 = Point(10, 20);\n"
" let p3 = add(&p1, &p2);\n"
" println!(\"&p3.0: {:p}\", &p3.0);\n"
" println!(\"{p1:?} + {p2:?} = {p3:?}\");\n"
"}\n"
"```"
#: src/ownership/borrowing.md:48
msgid "The Rust compiler can do return value optimization (RVO)."
msgstr "러스트 컴파일러는 반환값 최적화(RVO)를 수행할 수 있습니다."
#: src/ownership/borrowing.md:49
msgid ""
"In C++, copy elision has to be defined in the language specification because "
"constructors can have side effects. In Rust, this is not an issue at all. If "
"RVO did not happen, Rust will always perform a simple and efficient `memcpy` "
"copy."
msgstr ""
"C++에서 copy elision은 생성자의 부수효과 가능성이 있어 언어레벨의 정의가 필요"
"하지만 러스트에서는 문제가 되지 않습니다. 만약 RVO가 발생하지 않으면 러스트"
"는 항상 간단하고 효율적인 `memcpy`복사를 수행할 것입니다."
#: src/ownership/shared-unique-borrows.md:3
msgid "Rust puts constraints on the ways you can borrow values:"
msgstr "러스트에서는 값을 빌릴 때 다음과 같은 제약조건이 있습니다:"
#: src/ownership/shared-unique-borrows.md:5
msgid "You can have one or more `&T` values at any given time, _or_"
msgstr "한번에 하나 이상의 `&T` 값을 가지거나, _또는_"
#: src/ownership/shared-unique-borrows.md:6
msgid "You can have exactly one `&mut T` value."
msgstr "정확히 하나의 `&mut T` 값만을 가질 수 있습니다."
#: src/ownership/shared-unique-borrows.md:8
msgid ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let mut a: i32 = 10;\n"
" let b: &i32 = &a;\n"
"\n"
" {\n"
" let c: &mut i32 = &mut a;\n"
" *c = 20;\n"
" }\n"
"\n"
" println!(\"a: {a}\");\n"
" println!(\"b: {b}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let mut a: i32 = 10;\n"
" let b: &i32 = &a;\n"
"\n"
" {\n"
" let c: &mut i32 = &mut a;\n"
" *c = 20;\n"
" }\n"
"\n"
" println!(\"a: {a}\");\n"
" println!(\"b: {b}\");\n"
"}\n"
"```"
#: src/ownership/shared-unique-borrows.md:25
msgid ""
"The above code does not compile because `a` is borrowed as mutable (through "
"`c`) and as immutable (through `b`) at the same time."
msgstr ""
"위 코드 컴파일 되지 않습니다. 왜냐하면 `c`는 `a`를 가변 변수로 빌렸고, 이와 "
"동시에 `b`는 `a`를 불변 변수로 빌렸기 때문입니다."
#: src/ownership/shared-unique-borrows.md:26
msgid ""
"Move the `println!` statement for `b` before the scope that introduces `c` "
"to make the code compile."
msgstr ""
"`b`에 대한 `println!` 구분을 `c`가 있는 스코프 앞으로 이동하면 컴파일이 됩니"
"다."
#: src/ownership/shared-unique-borrows.md:27
msgid ""
"After that change, the compiler realizes that `b` is only ever used before "
"the new mutable borrow of `a` through `c`. This is a feature of the borrow "
"checker called \"non-lexical lifetimes\"."
msgstr ""
"이렇게 바꾸면, 컴파일러는 `c`가 `a`를 가변 변수로 빌리기 전에만 `b`가 사용된"
"다는 것을 확인할 수 있습니다. 빌림 검사기의 이러한 기능을 \"non-lexical "
"lifetime\" 이라고 합니다."
#: src/ownership/lifetimes.md:3
msgid "A borrowed value has a _lifetime_:"
msgstr "빌려온 값은 _수명_을 갖습니다:"
#: src/ownership/lifetimes.md:5
msgid "The lifetime can be implicit: `add(p1: &Point, p2: &Point) -> Point`."
msgstr "수명은 생략할 수 있습니다: `add(p1: &Point, p2: &Point) -> Point`."
#: src/ownership/lifetimes.md:6
msgid "Lifetimes can also be explicit: `&'a Point`, `&'document str`."
msgstr "물론 명시할 수도 있습니다: `&'a Point`, `&'document str`."
#: src/ownership/lifetimes.md:7 src/ownership/lifetimes-function-calls.md:23
msgid ""
"Read `&'a Point` as \"a borrowed `Point` which is valid for at least the "
"lifetime `a`\"."
msgstr ""
"`&'a Point` 는 `Point`의 수명이 최소한 `'a`라는 수명보다는 같거나 더 길다는 "
"것을 의미합니다."
#: src/ownership/lifetimes.md:9
msgid ""
"Lifetimes are always inferred by the compiler: you cannot assign a lifetime "
"yourself."
msgstr ""
"수명은 항상 컴파일러가 자동으로 추론합니다. 직접 수명을 지정할 수는 없습니다."
#: src/ownership/lifetimes.md:11
msgid ""
"Lifetime annotations create constraints; the compiler verifies that there is "
"a valid solution."
msgstr ""
"수명 표기(`'`)은 수명 추론시 제약조건이 됩니다. 컴파일러는 이 제약조건을 만족"
"시키는 유요한 수명을 추론할 수 있는지 검사를 합니다."
#: src/ownership/lifetimes.md:13
msgid ""
"Lifetimes for function arguments and return values must be fully specified, "
"but Rust allows lifetimes to be elided in most cases with [a few simple "
"rules](https://doc.rust-lang.org/nomicon/lifetime-elision.html)."
msgstr ""
"원래, 함수의 인자와 리턴값에는 수명을 설정해야 합니다. 그러나 [몇 가지 조건]"
"(https://doc.rust-lang.org/nomicon/lifetime-elision.html)을 만족하는 대부분"
"의 경우에는 생략할 수 있습니다."
#: src/ownership/lifetimes-function-calls.md:3
msgid ""
"In addition to borrowing its arguments, a function can return a borrowed "
"value:"
msgstr "함수는 인수를 빌리는 것 외에도 빌린 값을 반환할 수 있습니다:"
#: src/ownership/lifetimes-function-calls.md:5
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {\n"
" if p1.0 < p2.0 { p1 } else { p2 }\n"
"}\n"
"\n"
"fn main() {\n"
" let p1: Point = Point(10, 10);\n"
" let p2: Point = Point(20, 20);\n"
" let p3: &Point = left_most(&p1, &p2);\n"
" println!(\"left-most point: {:?}\", p3);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {\n"
" if p1.0 < p2.0 { p1 } else { p2 }\n"
"}\n"
"\n"
"fn main() {\n"
" let p1: Point = Point(10, 10);\n"
" let p2: Point = Point(20, 20);\n"
" let p3: &Point = left_most(&p1, &p2);\n"
" println!(\"left-most point: {:?}\", p3);\n"
"}\n"
"```"
#: src/ownership/lifetimes-function-calls.md:21
msgid "`'a` is a generic parameter, it is inferred by the compiler."
msgstr "`'a`는 제네릭 매개변수로 컴파일러로에 의해 추론됩니다."
#: src/ownership/lifetimes-function-calls.md:22
msgid "Lifetimes start with `'` and `'a` is a typical default name."
msgstr "수명의 이름은 `'` 로 시작하며 보통 `'a`를 많이 씁니다."
#: src/ownership/lifetimes-function-calls.md:25
msgid ""
"The _at least_ part is important when parameters are in different scopes."
msgstr ""
"매개변수들이 서로 다른 스코프에 있을 경우 \"최소한\"이라는 조건이 중요합니다."
#: src/ownership/lifetimes-function-calls.md:31
msgid ""
"Move the declaration of `p2` and `p3` into a new scope (`{ ... }`), "
"resulting in the following code:"
msgstr "`p2`와 `p3`를 새로운 범위(`{...}`)로 아래 코드와 같이 이동해 봅니다:"
#: src/ownership/lifetimes-function-calls.md:32
msgid ""
"```rust,ignore\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {\n"
" if p1.0 < p2.0 { p1 } else { p2 }\n"
"}\n"
"\n"
"fn main() {\n"
" let p1: Point = Point(10, 10);\n"
" let p3: &Point;\n"
" {\n"
" let p2: Point = Point(20, 20);\n"
" p3 = left_most(&p1, &p2);\n"
" }\n"
" println!(\"left-most point: {:?}\", p3);\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"#[derive(Debug)]\n"
"struct Point(i32, i32);\n"
"\n"
"fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {\n"
" if p1.0 < p2.0 { p1 } else { p2 }\n"
"}\n"
"\n"
"fn main() {\n"
" let p1: Point = Point(10, 10);\n"
" let p3: &Point;\n"
" {\n"
" let p2: Point = Point(20, 20);\n"
" p3 = left_most(&p1, &p2);\n"
" }\n"
" println!(\"left-most point: {:?}\", p3);\n"
"}\n"
"```"
#: src/ownership/lifetimes-function-calls.md:50
msgid "Note how this does not compile since `p3` outlives `p2`."
msgstr ""
"`p3`의 수명이 `p2` 보다 길기 때문에 이 예제는 컴파일되지 않음을 확인하시기 바"
"랍니다."
#: src/ownership/lifetimes-function-calls.md:52
msgid ""
"Reset the workspace and change the function signature to `fn left_most<'a, "
"'b>(p1: &'a Point, p2: &'a Point) -> &'b Point`. This will not compile "
"because the relationship between the lifetimes `'a` and `'b` is unclear."
msgstr ""
"작업공간을 초기화 한 후 함수 시그니처를 `fn left_most<'a, 'b>(p1: &'a Point, "
"p2: &'a Point) -> &'b Point`로 변경해 봅니다. 이 경우 `'a`와 `'b`사이의 관계"
"가 불분명하기 때문에 컴파일 되지 않습니다."
#: src/ownership/lifetimes-function-calls.md:53
msgid "Another way to explain it:"
msgstr "이 에러를 설명하는 또 다른 방법은 다음과 같습니다:"
#: src/ownership/lifetimes-function-calls.md:54
msgid ""
"Two references to two values are borrowed by a function and the function "
"returns another reference."
msgstr "이 함수는 두 값을 빌려서, 새로운 참조를 반환합니다."
#: src/ownership/lifetimes-function-calls.md:56
msgid ""
"It must have come from one of those two inputs (or from a global variable)."
msgstr ""
"이 반환된 참조는 두 입력 중 하나로 부터 와야 합니다. (아니면 전역 변수로 부"
"터)"
#: src/ownership/lifetimes-function-calls.md:57
msgid ""
"Which one is it? The compiler needs to know, so at the call site the "
"returned reference is not used for longer than a variable from where the "
"reference came from."
msgstr ""
"두 입력 중 어떤 것일까요? 컴파일러는 이를 알아야 합니다. 그래야만 함수 호출부"
"에서 봤을 때, 반환된 참조의 수명이 원래 값을 수명보다 길지 않음을 확인할 수 "
"있기 때문입니다."
#: src/ownership/lifetimes-data-structures.md:3
msgid ""
"If a data type stores borrowed data, it must be annotated with a lifetime:"
msgstr ""
"어떤 타입이 빌려온 데이터를 저장하고 있다면, 반드시 수명을 표시해야 합니다:"
#: src/ownership/lifetimes-data-structures.md:5
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Highlight<'doc>(&'doc str);\n"
"\n"
"fn erase(text: String) {\n"
" println!(\"Bye {text}!\");\n"
"}\n"
"\n"
"fn main() {\n"
" let text = String::from(\"The quick brown fox jumps over the lazy dog."
"\");\n"
" let fox = Highlight(&text[4..19]);\n"
" let dog = Highlight(&text[35..43]);\n"
" // erase(text);\n"
" println!(\"{fox:?}\");\n"
" println!(\"{dog:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Highlight<'doc>(&'doc str);\n"
"\n"
"fn erase(text: String) {\n"
" println!(\"Bye {text}!\");\n"
"}\n"
"\n"
"fn main() {\n"
" let text = String::from(\"The quick brown fox jumps over the lazy dog."
"\");\n"
" let fox = Highlight(&text[4..19]);\n"
" let dog = Highlight(&text[35..43]);\n"
" // erase(text);\n"
" println!(\"{fox:?}\");\n"
" println!(\"{dog:?}\");\n"
"}\n"
"```"
#: src/ownership/lifetimes-data-structures.md:25
msgid ""
"In the above example, the annotation on `Highlight` enforces that the data "
"underlying the contained `&str` lives at least as long as any instance of "
"`Highlight` that uses that data."
msgstr ""
"위의 예제에서 `Highlight`의 어노테이션(`<'doc>`)은 적어도 `Highlight` 인스턴"
"스가 살아있는 동안에는 그 내부의 `&str`가 가리키는 데이터 역시 살아있어야 한"
"다는 것을 의미합니다."
#: src/ownership/lifetimes-data-structures.md:26
msgid ""
"If `text` is consumed before the end of the lifetime of `fox` (or `dog`), "
"the borrow checker throws an error."
msgstr ""
"만약 `text`가 `fox` (혹은 `dog`)의 수명이 다하기 전에 `erase`함수 호출 등으"
"로 사라지게 된다면 빌림 검사기가 에러를 발생합니다."
#: src/ownership/lifetimes-data-structures.md:27
msgid ""
"Types with borrowed data force users to hold on to the original data. This "
"can be useful for creating lightweight views, but it generally makes them "
"somewhat harder to use."
msgstr ""
"빌린 데이터를 가지고 있는 타입은 사용자로 하여금 원본 데이터를 유지하도록 강"
"제합니다. 이런 타입은 경량 뷰(lightweight view)를 만드는데 유용하지만, 이 제"
"약 조건 때문에 이런 타입을 사용하는 것이 쉽지만은 않습니다."
#: src/ownership/lifetimes-data-structures.md:28
msgid "When possible, make data structures own their data directly."
msgstr ""
"따라서, 가능하다면, 구조체가 자신의 데이터를 직접 소유하도록 하는 것이 좋습니"
"다."
#: src/ownership/lifetimes-data-structures.md:29
msgid ""
"Some structs with multiple references inside can have more than one lifetime "
"annotation. This can be necessary if there is a need to describe lifetime "
"relationships between the references themselves, in addition to the lifetime "
"of the struct itself. Those are very advanced use cases."
msgstr ""
"한 구조체안에 여러 참조가 있으면서, 이 참조들의 수명이 서로 다르게 지정되는 "
"경우도 있습니다. 이는 참조와 그 구조체 간의 관계 뿐만이 아니라, 그 참조들 사"
"이의 수명 관계를 설명해야 할 경우에 필요합니다. 매우 고급 기술입니다."
#: src/exercises/day-1/afternoon.md:1
msgid "Day 1: Afternoon Exercises"
msgstr "1일차 오후 연습문제"
#: src/exercises/day-1/afternoon.md:3
msgid "We will look at two things:"
msgstr "이번 연습문제는 아래 두가지입니다:"
#: src/exercises/day-1/afternoon.md:5
msgid "A small book library,"
msgstr "작은 도서관,"
#: src/exercises/day-1/afternoon.md:7
msgid "Iterators and ownership (hard)."
msgstr "반복자와 소유권 (어려움)"
#: src/exercises/day-1/book-library.md:3
msgid ""
"We will learn much more about structs and the `Vec<T>` type tomorrow. For "
"now, you just need to know part of its API:"
msgstr ""
"우리는 내일 구조체와 `Vec<T>`에 대해 더 많은 것을 배울 것입니다. 일단 오늘은 "
"API의 일부만 알면 됩니다:"
#: src/exercises/day-1/book-library.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut vec = vec![10, 20];\n"
" vec.push(30);\n"
" let midpoint = vec.len() / 2;\n"
" println!(\"middle value: {}\", vec[midpoint]);\n"
" for item in &vec {\n"
" println!(\"item: {item}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut vec = vec![10, 20];\n"
" vec.push(30);\n"
" let midpoint = vec.len() / 2;\n"
" println!(\"middle value: {}\", vec[midpoint]);\n"
" for item in &vec {\n"
" println!(\"item: {item}\");\n"
" }\n"
"}\n"
"```"
#: src/exercises/day-1/book-library.md:18
msgid ""
"Use this to model a library's book collection. Copy the code below to "
"<https://play.rust-lang.org/> and update the types to make it compile:"
msgstr ""
"아래 코드는 도서관에 있는 도서 컬랙션을 모델링 합니다. 아래 코드를 <https://"
"play.rust-lang.org/>에 복사한 후, 컴파일 되도록 수정해 봅시다:"
#: src/exercises/day-1/book-library.md:21
msgid ""
"```rust,should_panic\n"
"struct Library {\n"
" books: Vec<Book>,\n"
"}\n"
"\n"
"struct Book {\n"
" title: String,\n"
" year: u16,\n"
"}\n"
"\n"
"impl Book {\n"
" // This is a constructor, used below.\n"
" fn new(title: &str, year: u16) -> Book {\n"
" Book {\n"
" title: String::from(title),\n"
" year,\n"
" }\n"
" }\n"
"}\n"
"\n"
"// Implement the methods below. Update the `self` parameter to\n"
"// indicate the method's required level of ownership over the object:\n"
"//\n"
"// - `&self` for shared read-only access,\n"
"// - `&mut self` for unique and mutable access,\n"
"// - `self` for unique access by value.\n"
"impl Library {\n"
" fn new() -> Library {\n"
" todo!(\"Initialize and return a `Library` value\")\n"
" }\n"
"\n"
" //fn len(self) -> usize {\n"
" // todo!(\"Return the length of `self.books`\")\n"
" //}\n"
"\n"
" //fn is_empty(self) -> bool {\n"
" // todo!(\"Return `true` if `self.books` is empty\")\n"
" //}\n"
"\n"
" //fn add_book(self, book: Book) {\n"
" // todo!(\"Add a new book to `self.books`\")\n"
" //}\n"
"\n"
" //fn print_books(self) {\n"
" // todo!(\"Iterate over `self.books` and each book's title and "
"year\")\n"
" //}\n"
"\n"
" //fn oldest_book(self) -> Option<&Book> {\n"
" // todo!(\"Return a reference to the oldest book (if any)\")\n"
" //}\n"
"}\n"
"\n"
"// This shows the desired behavior. Uncomment the code below and\n"
"// implement the missing methods. You will need to update the\n"
"// method signatures, including the \"self\" parameter! You may\n"
"// also need to update the variable bindings within main.\n"
"fn main() {\n"
" let library = Library::new();\n"
"\n"
" //println!(\"The library is empty: library.is_empty() -> {}\", library."
"is_empty());\n"
" //\n"
" //library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" //library.add_book(Book::new(\"Alice's Adventures in Wonderland\", "
"1865));\n"
" //\n"
" //println!(\"The library is no longer empty: library.is_empty() -> {}\", "
"library.is_empty());\n"
" //\n"
" //\n"
" //library.print_books();\n"
" //\n"
" //match library.oldest_book() {\n"
" // Some(book) => println!(\"The oldest book is {}\", book.title),\n"
" // None => println!(\"The library is empty!\"),\n"
" //}\n"
" //\n"
" //println!(\"The library has {} books\", library.len());\n"
" //library.print_books();\n"
"}\n"
"```"
msgstr ""
"```rust,should_panic\n"
"struct Library {\n"
" books: Vec<Book>,\n"
"}\n"
"\n"
"struct Book {\n"
" title: String,\n"
" year: u16,\n"
"}\n"
"\n"
"impl Book {\n"
" // This is a constructor, used below.\n"
" fn new(title: &str, year: u16) -> Book {\n"
" Book {\n"
" title: String::from(title),\n"
" year,\n"
" }\n"
" }\n"
"}\n"
"\n"
"// Implement the methods below. Update the `self` parameter to\n"
"// indicate the method's required level of ownership over the object:\n"
"//\n"
"// - `&self` for shared read-only access,\n"
"// - `&mut self` for unique and mutable access,\n"
"// - `self` for unique access by value.\n"
"impl Library {\n"
" fn new() -> Library {\n"
" todo!(\"Initialize and return a `Library` value\")\n"
" }\n"
"\n"
" //fn len(self) -> usize {\n"
" // todo!(\"Return the length of `self.books`\")\n"
" //}\n"
"\n"
" //fn is_empty(self) -> bool {\n"
" // todo!(\"Return `true` if `self.books` is empty\")\n"
" //}\n"
"\n"
" //fn add_book(self, book: Book) {\n"
" // todo!(\"Add a new book to `self.books`\")\n"
" //}\n"
"\n"
" //fn print_books(self) {\n"
" // todo!(\"Iterate over `self.books` and each book's title and "
"year\")\n"
" //}\n"
"\n"
" //fn oldest_book(self) -> Option<&Book> {\n"
" // todo!(\"Return a reference to the oldest book (if any)\")\n"
" //}\n"
"}\n"
"\n"
"// This shows the desired behavior. Uncomment the code below and\n"
"// implement the missing methods. You will need to update the\n"
"// method signatures, including the \"self\" parameter! You may\n"
"// also need to update the variable bindings within main.\n"
"fn main() {\n"
" let library = Library::new();\n"
"\n"
" //println!(\"The library is empty: library.is_empty() -> {}\", library."
"is_empty());\n"
" //\n"
" //library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" //library.add_book(Book::new(\"Alice's Adventures in Wonderland\", "
"1865));\n"
" //\n"
" //println!(\"The library is no longer empty: library.is_empty() -> {}\", "
"library.is_empty());\n"
" //\n"
" //\n"
" //library.print_books();\n"
" //\n"
" //match library.oldest_book() {\n"
" // Some(book) => println!(\"The oldest book is {}\", book.title),\n"
" // None => println!(\"The library is empty!\"),\n"
" //}\n"
" //\n"
" //println!(\"The library has {} books\", library.len());\n"
" //library.print_books();\n"
"}\n"
"```"
#: src/exercises/day-1/book-library.md:102
msgid "[Solution](solutions-afternoon.md#designing-a-library)"
msgstr "[해답](solutions-afternoon.md#designing-a-library)"
#: src/exercises/day-1/iterators-and-ownership.md:3
msgid ""
"The ownership model of Rust affects many APIs. An example of this is the "
"[`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) and "
"[`IntoIterator`](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html) "
"traits."
msgstr ""
"러스트의 소유권 모델은 많은 API에 반영이 되어 있습니다. 예를들어 [`Iterator`]"
"(https://doc.rust-lang.org/std/iter/trait.Iterator.html) 와 [`IntoIterator`]"
"(https://doc.rust-lang.org/std/iter/trait.IntoIterator.html) 같은 트레잇이 있"
"습니다."
#: src/exercises/day-1/iterators-and-ownership.md:8 src/bare-metal/no_std.md:28
msgid "`Iterator`"
msgstr "`Iterator`"
#: src/exercises/day-1/iterators-and-ownership.md:10
msgid ""
"Traits are like interfaces: they describe behavior (methods) for a type. The "
"`Iterator` trait simply says that you can call `next` until you get `None` "
"back:"
msgstr ""
"트레잇은 타입에 대한 행동(메서드)를 설명한다는 점에서 인터페이스와 유사합니"
"다. `Iterator`는 단순히 `None`이 나올때까지 `next`를 호출하는 것이 가능하다"
"는 것을 나타내는 트레잇입니다:"
#: src/exercises/day-1/iterators-and-ownership.md:13
msgid ""
"```rust\n"
"pub trait Iterator {\n"
" type Item;\n"
" fn next(&mut self) -> Option<Self::Item>;\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"pub trait Iterator {\n"
" type Item;\n"
" fn next(&mut self) -> Option<Self::Item>;\n"
"}\n"
"```"
#: src/exercises/day-1/iterators-and-ownership.md:20
msgid "You use this trait like this:"
msgstr "`Iterator` 트레잇은 이렇게 사용합니다:"
#: src/exercises/day-1/iterators-and-ownership.md:22
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let v: Vec<i8> = vec![10, 20, 30];\n"
" let mut iter = v.iter();\n"
"\n"
" println!(\"v[0]: {:?}\", iter.next());\n"
" println!(\"v[1]: {:?}\", iter.next());\n"
" println!(\"v[2]: {:?}\", iter.next());\n"
" println!(\"No more items: {:?}\", iter.next());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let v: Vec<i8> = vec![10, 20, 30];\n"
" let mut iter = v.iter();\n"
"\n"
" println!(\"v[0]: {:?}\", iter.next());\n"
" println!(\"v[1]: {:?}\", iter.next());\n"
" println!(\"v[2]: {:?}\", iter.next());\n"
" println!(\"No more items: {:?}\", iter.next());\n"
"}\n"
"```"
#: src/exercises/day-1/iterators-and-ownership.md:34
msgid "What is the type returned by the iterator? Test your answer here:"
msgstr "반복자가 반환하는 값들은 타입이 뭘까요? 여기서 답을 테스트 해 보세요:"
#: src/exercises/day-1/iterators-and-ownership.md:36
msgid ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let v: Vec<i8> = vec![10, 20, 30];\n"
" let mut iter = v.iter();\n"
"\n"
" let v0: Option<..> = iter.next();\n"
" println!(\"v0: {v0:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let v: Vec<i8> = vec![10, 20, 30];\n"
" let mut iter = v.iter();\n"
"\n"
" let v0: Option<..> = iter.next();\n"
" println!(\"v0: {v0:?}\");\n"
"}\n"
"```"
#: src/exercises/day-1/iterators-and-ownership.md:46
msgid "Why is this type used?"
msgstr "왜 이런 타입이 사용되는 것일까요?"
#: src/exercises/day-1/iterators-and-ownership.md:48
msgid "`IntoIterator`"
msgstr "`IntoIterator`"
#: src/exercises/day-1/iterators-and-ownership.md:50
msgid ""
"The `Iterator` trait tells you how to _iterate_ once you have created an "
"iterator. The related trait `IntoIterator` tells you how to create the "
"iterator:"
msgstr ""
"`Iterator` 트레잇은 생성된 반복자를 _사용_하는 방법을 알려줍니다. 반면 "
"`IntoIterator` 트레잇은 반복자를 _생성_하는 방법을 알려줍니다:"
#: src/exercises/day-1/iterators-and-ownership.md:53
msgid ""
"```rust\n"
"pub trait IntoIterator {\n"
" type Item;\n"
" type IntoIter: Iterator<Item = Self::Item>;\n"
"\n"
" fn into_iter(self) -> Self::IntoIter;\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"pub trait IntoIterator {\n"
" type Item;\n"
" type IntoIter: Iterator<Item = Self::Item>;\n"
"\n"
" fn into_iter(self) -> Self::IntoIter;\n"
"}\n"
"```"
#: src/exercises/day-1/iterators-and-ownership.md:62
msgid ""
"The syntax here means that every implementation of `IntoIterator` must "
"declare two types:"
msgstr "`IntoIterator`의 모든 구현은 반드시 다음의 두 타입을 선언해야합니다:"
#: src/exercises/day-1/iterators-and-ownership.md:65
msgid "`Item`: the type we iterate over, such as `i8`,"
msgstr "`Item`: `i8`과 같이 반복되는 값의 타입,"
#: src/exercises/day-1/iterators-and-ownership.md:66
msgid "`IntoIter`: the `Iterator` type returned by the `into_iter` method."
msgstr "`IntoIter`: `into_iter` 메서드에서 반환되는 `Iterator`타입."
#: src/exercises/day-1/iterators-and-ownership.md:68
msgid ""
"Note that `IntoIter` and `Item` are linked: the iterator must have the same "
"`Item` type, which means that it returns `Option<Item>`"
msgstr ""
"`IntoIter`에는 `Item`이 연결되어 있음을 주목하세요. `IntoIter` 반복자는 "
"`Item` 타입의 데이터를 가리켜야 합니다. 즉, 반복자는 `Option<Item>`을 리턴합"
"니다"
#: src/exercises/day-1/iterators-and-ownership.md:71
msgid "Like before, what is the type returned by the iterator?"
msgstr "이전과 마찬가지로, 반복자가 반환하는 타입은 무엇입니까?"
#: src/exercises/day-1/iterators-and-ownership.md:73
msgid ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let v: Vec<String> = vec![String::from(\"foo\"), String::"
"from(\"bar\")];\n"
" let mut iter = v.into_iter();\n"
"\n"
" let v0: Option<..> = iter.next();\n"
" println!(\"v0: {v0:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"fn main() {\n"
" let v: Vec<String> = vec![String::from(\"foo\"), String::"
"from(\"bar\")];\n"
" let mut iter = v.into_iter();\n"
"\n"
" let v0: Option<..> = iter.next();\n"
" println!(\"v0: {v0:?}\");\n"
"}\n"
"```"
#: src/exercises/day-1/iterators-and-ownership.md:83
msgid "`for` Loops"
msgstr "배열과 `for` 반복문"
#: src/exercises/day-1/iterators-and-ownership.md:85
msgid ""
"Now that we know both `Iterator` and `IntoIterator`, we can build `for` "
"loops. They call `into_iter()` on an expression and iterates over the "
"resulting iterator:"
msgstr ""
"자, 이제 우리는 `Iterator`와 `IntoIterator`를 알았으므로 `for` 루프를 만들 "
"수 있습니다. `for` 루프는 `into_iter()`를 호출하여 반복자를 만든 다음 그 반복"
"자를 이용하여 요소들을 반복해서 접근합니다:"
#: src/exercises/day-1/iterators-and-ownership.md:89
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let v: Vec<String> = vec![String::from(\"foo\"), String::"
"from(\"bar\")];\n"
"\n"
" for word in &v {\n"
" println!(\"word: {word}\");\n"
" }\n"
"\n"
" for word in v {\n"
" println!(\"word: {word}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let v: Vec<String> = vec![String::from(\"foo\"), String::"
"from(\"bar\")];\n"
"\n"
" for word in &v {\n"
" println!(\"word: {word}\");\n"
" }\n"
"\n"
" for word in v {\n"
" println!(\"word: {word}\");\n"
" }\n"
"}\n"
"```"
#: src/exercises/day-1/iterators-and-ownership.md:103
msgid "What is the type of `word` in each loop?"
msgstr "매 루프에서 `word`의 타입은 무엇입니까?"
#: src/exercises/day-1/iterators-and-ownership.md:105
msgid ""
"Experiment with the code above and then consult the documentation for [`impl "
"IntoIterator for &Vec<T>`](https://doc.rust-lang.org/std/vec/struct.Vec."
"html#impl-IntoIterator-for-%26'a+Vec%3CT,+A%3E) and [`impl IntoIterator for "
"Vec<T>`](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-IntoIterator-"
"for-Vec%3CT,+A%3E) to check your answers."
msgstr ""
"위 코드에서 실험 해 본 후, 다음 문서를 참조해서 답변을 확인하시기 바랍니다:"
"[`impl IntoIterator for &Vec<T>`](https://doc.rust-lang.org/std/vec/struct."
"Vec.html#impl-IntoIterator-for-%26'a+Vec%3CT,+A%3E), [`impl IntoIterator for "
"Vec<T>`](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-IntoIterator-"
"for-Vec%3CT%2C%20A%3E)"
#: src/welcome-day-2.md:1
msgid "Welcome to Day 2"
msgstr "2일차 개요"
#: src/welcome-day-2.md:3
msgid "Now that we have seen a fair amount of Rust, we will continue with:"
msgstr "상당한 분량의 러스트에 대해 보았고, 이어서 오늘 강의를 진행하겠습니다:"
#: src/welcome-day-2.md:5
msgid "Structs, enums, methods."
msgstr "구조체, 열거형, 메서드."
#: src/welcome-day-2.md:7
msgid "Pattern matching: destructuring enums, structs, and arrays."
msgstr "패턴 매칭: 열거형, 구조체 그리고 배열 분해."
#: src/welcome-day-2.md:9
msgid ""
"Control flow constructs: `if`, `if let`, `while`, `while let`, `break`, and "
"`continue`."
msgstr ""
"흐름 제어: `if`, `if let`, `while`, `while let`, `break`, 그리고 `continue`."
#: src/welcome-day-2.md:12
msgid ""
"The Standard Library: `String`, `Option` and `Result`, `Vec`, `HashMap`, "
"`Rc` and `Arc`."
msgstr ""
"표준 라이브러리: `String`, `Option` 과 `Result`, `Vec`, `HashMap`, `Rc` 그리"
"고 `Arc`."
#: src/welcome-day-2.md:15
msgid "Modules: visibility, paths, and filesystem hierarchy."
msgstr "모듈: 가시성, 경로 및 파일 시스템 계층."
#: src/structs.md:3
msgid "Like C and C++, Rust has support for custom structs:"
msgstr "C/C++ 와 마찬가지로 러스트는 커스텀 구조체를 지원합니다:"
#: src/structs.md:5
msgid ""
"```rust,editable\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"\n"
"fn main() {\n"
" let mut peter = Person {\n"
" name: String::from(\"Peter\"),\n"
" age: 27,\n"
" };\n"
" println!(\"{} is {} years old\", peter.name, peter.age);\n"
" \n"
" peter.age = 28;\n"
" println!(\"{} is {} years old\", peter.name, peter.age);\n"
" \n"
" let jackie = Person {\n"
" name: String::from(\"Jackie\"),\n"
" ..peter\n"
" };\n"
" println!(\"{} is {} years old\", jackie.name, jackie.age);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"\n"
"fn main() {\n"
" let mut peter = Person {\n"
" name: String::from(\"Peter\"),\n"
" age: 27,\n"
" };\n"
" println!(\"{} is {} years old\", peter.name, peter.age);\n"
" \n"
" peter.age = 28;\n"
" println!(\"{} is {} years old\", peter.name, peter.age);\n"
" \n"
" let jackie = Person {\n"
" name: String::from(\"Jackie\"),\n"
" ..peter\n"
" };\n"
" println!(\"{} is {} years old\", jackie.name, jackie.age);\n"
"}\n"
"```"
#: src/structs.md:31 src/enums.md:34 src/enums/sizes.md:28 src/methods.md:30
#: src/methods/example.md:46 src/pattern-matching.md:25
#: src/pattern-matching/match-guards.md:22 src/control-flow/blocks.md:43
msgid "Key Points:"
msgstr "키 포인트:"
#: src/structs.md:33
msgid "Structs work like in C or C++."
msgstr "구조체는 C/C++ 와 유사합니다."
#: src/structs.md:34
msgid "Like in C++, and unlike in C, no typedef is needed to define a type."
msgstr ""
"C++ 와 같지만 C와는 달리 타입을 정의하기 위해 'typedef'가 필요하지 않습니다."
#: src/structs.md:35
msgid "Unlike in C++, there is no inheritance between structs."
msgstr "C++ 와 달리 구조체 간 상속은 없습니다."
#: src/structs.md:36
msgid ""
"Methods are defined in an `impl` block, which we will see in following "
"slides."
msgstr ""
"메서드는 `impl`블록에 정의 합니다. 다음 슬라이드에서 확인 할 수 있습니다."
#: src/structs.md:37
msgid ""
"This may be a good time to let people know there are different types of "
"structs. "
msgstr ""
"사람들에게 다른 종류의 구조체가 있음을 알게 하기에 좋은 시간일 것입니다. "
#: src/structs.md:38
msgid ""
"Zero-sized structs `e.g., struct Foo;` might be used when implementing a "
"trait on some type but don’t have any data that you want to store in the "
"value itself. "
msgstr ""
"0 크기 구조체(예: `struct Foo;`)는 데이터를 가지고 있지 않지만 특정 타입의 트"
"레잇을 구현할 때 유용합니다. "
#: src/structs.md:39
msgid ""
"The next slide will introduce Tuple structs, used when the field names are "
"not important."
msgstr ""
"다음 슬라이드에서는 필드 이름이 덜 중요할 때 사용할 수 있는 튜플 구조체를 소"
"개합니다."
#: src/structs.md:40
msgid ""
"The syntax `..peter` allows us to copy the majority of the fields from the "
"old struct without having to explicitly type it all out. It must always be "
"the last element."
msgstr ""
"`..peter` 문법은 한 구조체에서 다른 구조체로 대부분의 값을 복사하려고 하는 경"
"우에 하나하나 타이핑하는 수고를 덜어줍니다. 반드시 맨 마지막에 와야 합니다."
#: src/structs/tuple-structs.md:3
msgid "If the field names are unimportant, you can use a tuple struct:"
msgstr "각 필드 이름이 중요하지 않다면 튜플 구조체를 사용할 수 있습니다:"
#: src/structs/tuple-structs.md:5
msgid ""
"```rust,editable\n"
"struct Point(i32, i32);\n"
"\n"
"fn main() {\n"
" let p = Point(17, 23);\n"
" println!(\"({}, {})\", p.0, p.1);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"struct Point(i32, i32);\n"
"\n"
"fn main() {\n"
" let p = Point(17, 23);\n"
" println!(\"({}, {})\", p.0, p.1);\n"
"}\n"
"```"
#: src/structs/tuple-structs.md:14
msgid "This is often used for single-field wrappers (called newtypes):"
msgstr ""
"튜플 구조체는 종종 단일 필드의 래퍼(wrapper, 러스트에서 뉴타입(newtype)이라"
"고 부름)로 사용됩니다:"
#: src/structs/tuple-structs.md:16
msgid ""
"```rust,editable,compile_fail\n"
"struct PoundsOfForce(f64);\n"
"struct Newtons(f64);\n"
"\n"
"fn compute_thruster_force() -> PoundsOfForce {\n"
" todo!(\"Ask a rocket scientist at NASA\")\n"
"}\n"
"\n"
"fn set_thruster_force(force: Newtons) {\n"
" // ...\n"
"}\n"
"\n"
"fn main() {\n"
" let force = compute_thruster_force();\n"
" set_thruster_force(force);\n"
"}\n"
"\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"struct PoundsOfForce(f64);\n"
"struct Newtons(f64);\n"
"\n"
"fn compute_thruster_force() -> PoundsOfForce {\n"
" todo!(\"Ask a rocket scientist at NASA\")\n"
"}\n"
"\n"
"fn set_thruster_force(force: Newtons) {\n"
" // ...\n"
"}\n"
"\n"
"fn main() {\n"
" let force = compute_thruster_force();\n"
" set_thruster_force(force);\n"
"}\n"
"\n"
"```"
#: src/structs/tuple-structs.md:37
msgid ""
"Newtypes are a great way to encode additional information about the value in "
"a primitive type, for example:"
msgstr ""
"뉴타입은 기본 타입에 부가적인 의미를 더하는 좋은 방법입니다. 예를 들어:"
#: src/structs/tuple-structs.md:38
msgid "The number is measured in some units: `Newtons` in the example above."
msgstr "숫자값에 단위를 표시할 수 있음: 위에서 `Newtons`이 그 예입니다."
#: src/structs/tuple-structs.md:39
msgid ""
"The value passed some validation when it was created, so you no longer have "
"to validate it again at every use: 'PhoneNumber(String)`or`OddNumber(u32)\\`."
msgstr ""
"값이 생성될 때 이미 유효성 검사를 통과 했으므로 추가적인 검사가 필요없습니"
"다: `PhoneNumber(String)`또는 `OddNumber(u32)`."
#: src/structs/tuple-structs.md:40
msgid ""
"Demonstrate how to add a `f64` value to a `Newtons` type by accessing the "
"single field in the newtype."
msgstr "`Newtons` 타입의 값에 `f64` 값을 더하는 방법을 보여주세요."
#: src/structs/tuple-structs.md:41
msgid ""
"Rust generally doesn’t like inexplicit things, like automatic unwrapping or "
"for instance using booleans as integers."
msgstr ""
"러스트는 분명하지 않은 것을 싫어합니다. 예를 들면 자동으로 unwrap하거나 불리"
"언 값을 정수 값으로 사용하는 것들이 그렇습니다."
#: src/structs/tuple-structs.md:42
msgid "Operator overloading is discussed on Day 3 (generics)."
msgstr "연산자 재정의는 3일차 제네릭 부분에서 다룹니다."
#: src/structs/tuple-structs.md:43
msgid ""
"The example is a subtle reference to the [Mars Climate Orbiter](https://en."
"wikipedia.org/wiki/Mars_Climate_Orbiter) failure."
msgstr ""
"이는 [화성 기후 궤도선 (Mars Climate Orbiter)](https://en.wikipedia.org/wiki/"
"Mars_Climate_Orbiter)의 실패 원인으로 지목된 도량형 입력 오류를 보여줍니다."
#: src/structs/field-shorthand.md:3
msgid ""
"If you already have variables with the right names, then you can create the "
"struct using a shorthand:"
msgstr ""
"구조체 필드와 동일한 이름의 변수가 있다면 아래와 같이 \"짧은 문법\"으로 구조"
"체를 생성할 수 있습니다:"
#: src/structs/field-shorthand.md:6
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"\n"
"impl Person {\n"
" fn new(name: String, age: u8) -> Person {\n"
" Person { name, age }\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let peter = Person::new(String::from(\"Peter\"), 27);\n"
" println!(\"{peter:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"\n"
"impl Person {\n"
" fn new(name: String, age: u8) -> Person {\n"
" Person { name, age }\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let peter = Person::new(String::from(\"Peter\"), 27);\n"
" println!(\"{peter:?}\");\n"
"}\n"
"```"
#: src/structs/field-shorthand.md:27
msgid ""
"The `new` function could be written using `Self` as a type, as it is "
"interchangeable with the struct type name"
msgstr ""
"`new`함수를 다음처럼 구조체 이름 대신 `Self`를 사용하여 작성해도 됩니다"
#: src/structs/field-shorthand.md:29
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"impl Person {\n"
" fn new(name: String, age: u8) -> Self {\n"
" Self { name, age }\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"impl Person {\n"
" fn new(name: String, age: u8) -> Self {\n"
" Self { name, age }\n"
" }\n"
"}\n"
"```"
#: src/structs/field-shorthand.md:41
msgid ""
"Implement the `Default` trait for the struct. Define some fields and use the "
"default values for the other fields."
msgstr ""
"`Default` 트레잇을 구현해보세요. 필드 몇개는 초기화하고 나머지 필드는 디폴트 "
"값을 사용할 수 있습니다."
#: src/structs/field-shorthand.md:43
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"impl Default for Person {\n"
" fn default() -> Person {\n"
" Person {\n"
" name: \"Bot\".to_string(),\n"
" age: 0,\n"
" }\n"
" }\n"
"}\n"
"fn create_default() {\n"
" let tmp = Person {\n"
" ..Person::default()\n"
" };\n"
" let tmp = Person {\n"
" name: \"Sam\".to_string(),\n"
" ..Person::default()\n"
" };\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"impl Default for Person {\n"
" fn default() -> Person {\n"
" Person {\n"
" name: \"Bot\".to_string(),\n"
" age: 0,\n"
" }\n"
" }\n"
"}\n"
"fn create_default() {\n"
" let tmp = Person {\n"
" ..Person::default()\n"
" };\n"
" let tmp = Person {\n"
" name: \"Sam\".to_string(),\n"
" ..Person::default()\n"
" };\n"
"}\n"
"```"
#: src/structs/field-shorthand.md:68
msgid "Methods are defined in the `impl` block."
msgstr "메서드는 `impl` 블록에 정의됩니다."
#: src/structs/field-shorthand.md:69
msgid ""
"Use struct update syntax to define a new structure using `peter`. Note that "
"the variable `peter` will no longer be accessible afterwards."
msgstr ""
"`peter`와 구조체 업데이트 문법을 사용하여 새로운 구조체 인스턴스를 만들어보세"
"요. 이때, `peter`는 더이상 사용할 수 없게 됩니다."
#: src/structs/field-shorthand.md:70
msgid ""
"Use `{:#?}` when printing structs to request the `Debug` representation."
msgstr "구조체를 `Debug` 형태로 출력하려면 `{:#?}`를 사용하세요."
#: src/enums.md:3
msgid ""
"The `enum` keyword allows the creation of a type which has a few different "
"variants:"
msgstr "`enum` 키워드는 몇가지 유형(variant)으로 표현되는 타입을 생성합니다:"
#: src/enums.md:6
msgid ""
"```rust,editable\n"
"fn generate_random_number() -> i32 {\n"
" // Implementation based on https://xkcd.com/221/\n"
" 4 // Chosen by fair dice roll. Guaranteed to be random.\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"enum CoinFlip {\n"
" Heads,\n"
" Tails,\n"
"}\n"
"\n"
"fn flip_coin() -> CoinFlip {\n"
" let random_number = generate_random_number();\n"
" if random_number % 2 == 0 {\n"
" return CoinFlip::Heads;\n"
" } else {\n"
" return CoinFlip::Tails;\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"You got: {:?}\", flip_coin());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn generate_random_number() -> i32 {\n"
" // Implementation based on https://xkcd.com/221/\n"
" 4 // Chosen by fair dice roll. Guaranteed to be random.\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"enum CoinFlip {\n"
" Heads,\n"
" Tails,\n"
"}\n"
"\n"
"fn flip_coin() -> CoinFlip {\n"
" let random_number = generate_random_number();\n"
" if random_number % 2 == 0 {\n"
" return CoinFlip::Heads;\n"
" } else {\n"
" return CoinFlip::Tails;\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"You got: {:?}\", flip_coin());\n"
"}\n"
"```"
#: src/enums.md:36
msgid "Enumerations allow you to collect a set of values under one type"
msgstr "열거형은 값들의 집합을 하나의 타입으로 표현할 수 있게 합니다"
#: src/enums.md:37
msgid ""
"This page offers an enum type `CoinFlip` with two variants `Heads` and "
"`Tails`. You might note the namespace when using variants."
msgstr ""
"위의 `CoinFlip` 열거형 타입은 `Heads`와 `Tail` 두 가지 variant를 가집니다. 열"
"거형 타입의 variant는 네임스페이스를 붙여서 사용합니다."
#: src/enums.md:38
msgid "This might be a good time to compare Structs and Enums:"
msgstr "구조체와 열거형을 비교해 보겠습니다:"
#: src/enums.md:39
msgid ""
"In both, you can have a simple version without fields (unit struct) or one "
"with different types of fields (variant payloads). "
msgstr ""
"구조체나 열거형 모두, 필드가 하나도 없는 단순한 형태도 가능 하고, 여러 타입"
"의 필드를 가질 수도 있습니다. "
#: src/enums.md:40
msgid "In both, associated functions are defined within an `impl` block."
msgstr "둘 다 연관함수를 `impl`블록으로 정의 할 수 있습니다."
#: src/enums.md:41
msgid ""
"You could even implement the different variants of an enum with separate "
"structs but then they wouldn’t be the same type as they would if they were "
"all defined in an enum. "
msgstr ""
"열거형 타입의 각 variant를 별도의 구조체로 정의할 수도 있지만, 그러면 열거형"
"을 사용했을 때처럼 하나의 타입으로 취급할 수 없습니다. "
#: src/enums/variant-payloads.md:3
msgid ""
"You can define richer enums where the variants carry data. You can then use "
"the `match` statement to extract the data from each variant:"
msgstr ""
"좀더 복잡한 열거형의 경우 variant에 데이터(payload)를 포함시키도 합니다. 각 "
"variant에 담긴 데이터는 `match`문을 이용해 추출합니다:"
#: src/enums/variant-payloads.md:6
msgid ""
"```rust,editable\n"
"enum WebEvent {\n"
" PageLoad, // Variant without payload\n"
" KeyPress(char), // Tuple struct variant\n"
" Click { x: i64, y: i64 }, // Full struct variant\n"
"}\n"
"\n"
"#[rustfmt::skip]\n"
"fn inspect(event: WebEvent) {\n"
" match event {\n"
" WebEvent::PageLoad => println!(\"page loaded\"),\n"
" WebEvent::KeyPress(c) => println!(\"pressed '{c}'\"),\n"
" WebEvent::Click { x, y } => println!(\"clicked at x={x}, y={y}\"),\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let load = WebEvent::PageLoad;\n"
" let press = WebEvent::KeyPress('x');\n"
" let click = WebEvent::Click { x: 20, y: 80 };\n"
"\n"
" inspect(load);\n"
" inspect(press);\n"
" inspect(click);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"enum WebEvent {\n"
" PageLoad, // 페이로드가 없는 유형\n"
" KeyPress(char), // 튜플 구조체 유형\n"
" Click { x: i64, y: i64 }, // 완전한 구조체 유형\n"
"}\n"
"\n"
"#[rustfmt::skip]\n"
"fn inspect(event: WebEvent) {\n"
" match event {\n"
" WebEvent::PageLoad => println!(\"page loaded\"),\n"
" WebEvent::KeyPress(c) => println!(\"pressed '{c}'\"),\n"
" WebEvent::Click { x, y } => println!(\"clicked at x={x}, y={y}\"),\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let load = WebEvent::PageLoad;\n"
" let press = WebEvent::KeyPress('x');\n"
" let click = WebEvent::Click { x: 20, y: 80 };\n"
"\n"
" inspect(load);\n"
" inspect(press);\n"
" inspect(click);\n"
"}\n"
"```"
#: src/enums/variant-payloads.md:35
msgid ""
"The values in the enum variants can only be accessed after being pattern "
"matched. The pattern binds references to the fields in the \"match arm\" "
"after the `=>`."
msgstr ""
"열거형 안의 값은 패턴 매칭이 되고 난 이후에만 접근 가능합니다. 그 값에 대한 "
"레퍼런스는 `=>` 이후에 사용가능합니다."
#: src/enums/variant-payloads.md:36
msgid ""
"The expression is matched against the patterns from top to bottom. There is "
"no fall-through like in C or C++."
msgstr ""
"매치 패턴들은 위에서 아래로 순서에 따라 검사합니다. C나 C++에서와 같은 fall-"
"through는 없습니다."
#: src/enums/variant-payloads.md:37
msgid ""
"The match expression has a value. The value is the last expression in the "
"match arm which was executed."
msgstr ""
"매치 표현식 자체는 값을 가집니다. 그 값은 매칭이 된 패턴에서 가장 마지막에 수"
"행된 표현식이 됩니다."
#: src/enums/variant-payloads.md:38
msgid ""
"Starting from the top we look for what pattern matches the value then run "
"the code following the arrow. Once we find a match, we stop. "
msgstr ""
"가장 위에서 부터 어떤 패턴이 주어진 값과 매칭하는지 검사한 다음, 매칭된 것이 "
"발견되면 화살표를 따라 코드를 수행합니다. 한 번 매칭이 되고 코드가 수행이 되"
"면, 더이상의 매칭은 없습니다. "
#: src/enums/variant-payloads.md:39
msgid ""
"Demonstrate what happens when the search is inexhaustive. Note the advantage "
"the Rust compiler provides by confirming when all cases are handled. "
msgstr ""
"매칭 패턴들이 불충분 하다면 어떤 일이 일어나는지 설명하세요. 러스트 컴파일러"
"는 모든 가능한 케이스들이 핸들링 되는지 체크한다는 점을 상기시키세요. "
#: src/enums/variant-payloads.md:40
msgid "`match` inspects a hidden discriminant field in the `enum`."
msgstr ""
"`match`는 주어진 열거형 값이 실제로 어떤 variant인지 판단하기 위해, 그 "
"variant의 종류가 기록된, 숨겨진 필드(식별자)의 값을 검사합니다."
#: src/enums/variant-payloads.md:41
msgid ""
"It is possible to retrieve the discriminant by calling `std::mem::"
"discriminant()`"
msgstr "`std::mem::discriminant()`를 이용하여 식별자를 얻을 수도 있습니다"
#: src/enums/variant-payloads.md:42
msgid ""
"This is useful, for example, if implementing `PartialEq` for structs where "
"comparing field values doesn't affect equality."
msgstr ""
"이는 각 필드 값을 굳이 비교할 필요 없는 구조체에 대해 `PartialEq` 트레잇을 구"
"현할 때 유용합니다."
#: src/enums/variant-payloads.md:43
msgid ""
"`WebEvent::Click { ... }` is not exactly the same as `WebEvent::"
"Click(Click)` with a top level `struct Click { ... }`. The inlined version "
"cannot implement traits, for example."
msgstr ""
"`WebEvent::Click { ... }`은 최상위 레벨 구조체 `struct Click {...}`를 따로 정"
"의하고 `WebEvent::Click(Click)`처럼 튜플 형태로 정의한 것과 정확히 같진 않습"
"니다. 예를 들어 `WebEvent::Click { ... }` 로 정의한 경우, 구조체 형태와 유사"
"하지만 트레잇을 구현 할 수 없습니다."
#: src/enums/sizes.md:3
msgid ""
"Rust enums are packed tightly, taking constraints due to alignment into "
"account:"
msgstr ""
"러스트의 열거형은 정렬(alignment)로 인한 제약을 고려하여 크기를 빽빽하게 잡습"
"니다:"
#: src/enums/sizes.md:5
msgid ""
"```rust,editable\n"
"use std::any::type_name;\n"
"use std::mem::{align_of, size_of};\n"
"\n"
"fn dbg_size<T>() {\n"
" println!(\"{}: size {} bytes, align: {} bytes\",\n"
" type_name::<T>(), size_of::<T>(), align_of::<T>());\n"
"}\n"
"\n"
"enum Foo {\n"
" A,\n"
" B,\n"
"}\n"
"\n"
"fn main() {\n"
" dbg_size::<Foo>();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::any::type_name;\n"
"use std::mem::{align_of, size_of};\n"
"\n"
"fn dbg_size<T>() {\n"
" println!(\"{}: size {} bytes, align: {} bytes\",\n"
" type_name::<T>(), size_of::<T>(), align_of::<T>());\n"
"}\n"
"\n"
"enum Foo {\n"
" A,\n"
" B,\n"
"}\n"
"\n"
"fn main() {\n"
" dbg_size::<Foo>();\n"
"}\n"
"```"
#: src/enums/sizes.md:24
msgid ""
"See the [Rust Reference](https://doc.rust-lang.org/reference/type-layout."
"html)."
msgstr ""
"자세한 사항은 [공식문서](https://doc.rust-lang.org/reference/type-layout."
"html)를 확인하세요."
#: src/enums/sizes.md:30
msgid ""
"Internally Rust is using a field (discriminant) to keep track of the enum "
"variant."
msgstr ""
"러스트는 열거형 variant를 구분하기 위해 내부적으로 식별자(discriminant) 필드"
"를 사용합니다."
#: src/enums/sizes.md:32
msgid ""
"You can control the discriminant if needed (e.g., for compatibility with C):"
msgstr "C와의 연동을 위해 식별자 값을 직접 지정할 수도 있습니다:"
#: src/enums/sizes.md:34
msgid ""
"```rust,editable\n"
"#[repr(u32)]\n"
"enum Bar {\n"
" A, // 0\n"
" B = 10000,\n"
" C, // 10001\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"A: {}\", Bar::A as u32);\n"
" println!(\"B: {}\", Bar::B as u32);\n"
" println!(\"C: {}\", Bar::C as u32);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[repr(u32)]\n"
"enum Bar {\n"
" A, // 0\n"
" B = 10000,\n"
" C, // 10001\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"A: {}\", Bar::A as u32);\n"
" println!(\"B: {}\", Bar::B as u32);\n"
" println!(\"C: {}\", Bar::C as u32);\n"
"}\n"
"```"
#: src/enums/sizes.md:49
msgid ""
"Without `repr`, the discriminant type takes 2 bytes, because 10001 fits 2 "
"bytes."
msgstr ""
"`repr` 속성이 없다면 10001이 2 바이트로 표현가능하기 때문에 식별자의 타입 크"
"기는 2 바이트가 됩니다."
#: src/enums/sizes.md:53
msgid "Try out other types such as"
msgstr "다른 타입들도 확인해보세요"
#: src/enums/sizes.md:55
msgid "`dbg_size!(bool)`: size 1 bytes, align: 1 bytes,"
msgstr "`dbg_size!(bool)`: 크기 1 바이트, 정렬: 1 바이트,"
#: src/enums/sizes.md:56
msgid ""
"`dbg_size!(Option<bool>)`: size 1 bytes, align: 1 bytes (niche optimization, "
"see below),"
msgstr ""
"`dbg_size!(Option<bool>)`: 크기 1 바이트, 정렬: 1 바이트 (니치 최적화, 아래 "
"설명 참조)"
#: src/enums/sizes.md:57
msgid "`dbg_size!(&i32)`: size 8 bytes, align: 8 bytes (on a 64-bit machine),"
msgstr "`dbg_size!(&i32)`: 크기 8 바이트, 정렬: 8 바이트 (64비트 머신인 경우)"
#: src/enums/sizes.md:58
msgid ""
"`dbg_size!(Option<&i32>)`: size 8 bytes, align: 8 bytes (null pointer "
"optimization, see below)."
msgstr ""
"`dbg_size!(Option<&i32>)`: 크기 8 바이트, 정렬: 8 바이트 (널포인터 최적화, 아"
"래 설명 참조)"
#: src/enums/sizes.md:60
msgid ""
"Niche optimization: Rust will merge unused bit patterns for the enum "
"discriminant."
msgstr ""
"니치 최적화: 러스트는 열거형 식별자를 사용되지 않은 비트 패턴과 병합합니다."
#: src/enums/sizes.md:63
msgid ""
"Null pointer optimization: For [some types](https://doc.rust-lang.org/std/"
"option/#representation), Rust guarantees that `size_of::<T>()` equals "
"`size_of::<Option<T>>()`."
msgstr ""
"널포인터 최적화: [어떤 타입들](https://doc.rust-lang.org/std/option/"
"#representation)에 대해서 러스트는 `size_of::<T>()`가 `size_of::"
"<Option<T>>()`와 같은 것을 보장합니다."
#: src/enums/sizes.md:67
msgid ""
"Example code if you want to show how the bitwise representation _may_ look "
"like in practice. It's important to note that the compiler provides no "
"guarantees regarding this representation, therefore this is totally unsafe."
msgstr ""
"실제로 널포인터 최적화가 적용된 것을 확인하고 싶다면 아래의 예제코드를 사용하"
"세요. 주의할 점은, 여기에서 보여주는 비트 패턴이 컴파일러가 보장해 주는 것은 "
"아니라는 점입니다. 여기에 의존하는 것은 완전히 unsafe합니다."
#: src/enums/sizes.md:70
msgid ""
"```rust,editable\n"
"use std::mem::transmute;\n"
"\n"
"macro_rules! dbg_bits {\n"
" ($e:expr, $bit_type:ty) => {\n"
" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, "
"$bit_type>($e));\n"
" };\n"
"}\n"
"\n"
"fn main() {\n"
" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n"
" // representation of types.\n"
" unsafe {\n"
" println!(\"Bitwise representation of bool\");\n"
" dbg_bits!(false, u8);\n"
" dbg_bits!(true, u8);\n"
"\n"
" println!(\"Bitwise representation of Option<bool>\");\n"
" dbg_bits!(None::<bool>, u8);\n"
" dbg_bits!(Some(false), u8);\n"
" dbg_bits!(Some(true), u8);\n"
"\n"
" println!(\"Bitwise representation of Option<Option<bool>>\");\n"
" dbg_bits!(Some(Some(false)), u8);\n"
" dbg_bits!(Some(Some(true)), u8);\n"
" dbg_bits!(Some(None::<bool>), u8);\n"
" dbg_bits!(None::<Option<bool>>, u8);\n"
"\n"
" println!(\"Bitwise representation of Option<&i32>\");\n"
" dbg_bits!(None::<&i32>, usize);\n"
" dbg_bits!(Some(&0i32), usize);\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::mem::transmute;\n"
"\n"
"macro_rules! dbg_bits {\n"
" ($e:expr, $bit_type:ty) => {\n"
" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, "
"$bit_type>($e));\n"
" };\n"
"}\n"
"\n"
"fn main() {\n"
" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n"
" // representation of types.\n"
" unsafe {\n"
" println!(\"Bitwise representation of bool\");\n"
" dbg_bits!(false, u8);\n"
" dbg_bits!(true, u8);\n"
"\n"
" println!(\"Bitwise representation of Option<bool>\");\n"
" dbg_bits!(None::<bool>, u8);\n"
" dbg_bits!(Some(false), u8);\n"
" dbg_bits!(Some(true), u8);\n"
"\n"
" println!(\"Bitwise representation of Option<Option<bool>>\");\n"
" dbg_bits!(Some(Some(false)), u8);\n"
" dbg_bits!(Some(Some(true)), u8);\n"
" dbg_bits!(Some(None::<bool>), u8);\n"
" dbg_bits!(None::<Option<bool>>, u8);\n"
"\n"
" println!(\"Bitwise representation of Option<&i32>\");\n"
" dbg_bits!(None::<&i32>, usize);\n"
" dbg_bits!(Some(&0i32), usize);\n"
" }\n"
"}\n"
"```"
#: src/enums/sizes.md:105
msgid ""
"More complex example if you want to discuss what happens when we chain more "
"than 256 `Option`s together."
msgstr ""
"아래는 좀 더 복잡한 예제입니다. 256개 이상의 `Option`이 중첩되어 연결되어 있"
"을 경우 어떻게 되는지 보여줍니다."
#: src/enums/sizes.md:107
msgid ""
"```rust,editable\n"
"#![recursion_limit = \"1000\"]\n"
"\n"
"use std::mem::transmute;\n"
"\n"
"macro_rules! dbg_bits {\n"
" ($e:expr, $bit_type:ty) => {\n"
" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, "
"$bit_type>($e));\n"
" };\n"
"}\n"
"\n"
"// Macro to wrap a value in 2^n Some() where n is the number of \"@\" "
"signs.\n"
"// Increasing the recursion limit is required to evaluate this macro.\n"
"macro_rules! many_options {\n"
" ($value:expr) => { Some($value) };\n"
" ($value:expr, @) => {\n"
" Some(Some($value))\n"
" };\n"
" ($value:expr, @ $($more:tt)+) => {\n"
" many_options!(many_options!($value, $($more)+), $($more)+)\n"
" };\n"
"}\n"
"\n"
"fn main() {\n"
" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n"
" // representation of types.\n"
" unsafe {\n"
" assert_eq!(many_options!(false), Some(false));\n"
" assert_eq!(many_options!(false, @), Some(Some(false)));\n"
" assert_eq!(many_options!(false, @@), "
"Some(Some(Some(Some(false)))));\n"
"\n"
" println!(\"Bitwise representation of a chain of 128 Option's.\");\n"
" dbg_bits!(many_options!(false, @@@@@@@), u8);\n"
" dbg_bits!(many_options!(true, @@@@@@@), u8);\n"
"\n"
" println!(\"Bitwise representation of a chain of 256 Option's.\");\n"
" dbg_bits!(many_options!(false, @@@@@@@@), u16);\n"
" dbg_bits!(many_options!(true, @@@@@@@@), u16);\n"
"\n"
" println!(\"Bitwise representation of a chain of 257 Option's.\");\n"
" dbg_bits!(many_options!(Some(false), @@@@@@@@), u16);\n"
" dbg_bits!(many_options!(Some(true), @@@@@@@@), u16);\n"
" dbg_bits!(many_options!(None::<bool>, @@@@@@@@), u16);\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#![recursion_limit = \"1000\"]\n"
"\n"
"use std::mem::transmute;\n"
"\n"
"macro_rules! dbg_bits {\n"
" ($e:expr, $bit_type:ty) => {\n"
" println!(\"- {}: {:#x}\", stringify!($e), transmute::<_, "
"$bit_type>($e));\n"
" };\n"
"}\n"
"\n"
"// Macro to wrap a value in 2^n Some() where n is the number of \"@\" "
"signs.\n"
"// Increasing the recursion limit is required to evaluate this macro.\n"
"macro_rules! many_options {\n"
" ($value:expr) => { Some($value) };\n"
" ($value:expr, @) => {\n"
" Some(Some($value))\n"
" };\n"
" ($value:expr, @ $($more:tt)+) => {\n"
" many_options!(many_options!($value, $($more)+), $($more)+)\n"
" };\n"
"}\n"
"\n"
"fn main() {\n"
" // TOTALLY UNSAFE. Rust provides no guarantees about the bitwise\n"
" // representation of types.\n"
" unsafe {\n"
" assert_eq!(many_options!(false), Some(false));\n"
" assert_eq!(many_options!(false, @), Some(Some(false)));\n"
" assert_eq!(many_options!(false, @@), "
"Some(Some(Some(Some(false)))));\n"
"\n"
" println!(\"Bitwise representation of a chain of 128 Option's.\");\n"
" dbg_bits!(many_options!(false, @@@@@@@), u8);\n"
" dbg_bits!(many_options!(true, @@@@@@@), u8);\n"
"\n"
" println!(\"Bitwise representation of a chain of 256 Option's.\");\n"
" dbg_bits!(many_options!(false, @@@@@@@@), u16);\n"
" dbg_bits!(many_options!(true, @@@@@@@@), u16);\n"
"\n"
" println!(\"Bitwise representation of a chain of 257 Option's.\");\n"
" dbg_bits!(many_options!(Some(false), @@@@@@@@), u16);\n"
" dbg_bits!(many_options!(Some(true), @@@@@@@@), u16);\n"
" dbg_bits!(many_options!(None::<bool>, @@@@@@@@), u16);\n"
" }\n"
"}\n"
"```"
#: src/methods.md:3
msgid ""
"Rust allows you to associate functions with your new types. You do this with "
"an `impl` block:"
msgstr ""
"러스트에서 선언된 타입에 대해 `impl`블록에 함수를 선언하여 메서드를 연결 할 "
"수 있습니다:"
#: src/methods.md:6
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"\n"
"impl Person {\n"
" fn say_hello(&self) {\n"
" println!(\"Hello, my name is {}\", self.name);\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let peter = Person {\n"
" name: String::from(\"Peter\"),\n"
" age: 27,\n"
" };\n"
" peter.say_hello();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Person {\n"
" name: String,\n"
" age: u8,\n"
"}\n"
"\n"
"impl Person {\n"
" fn say_hello(&self) {\n"
" println!(\"Hello, my name is {}\", self.name);\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let peter = Person {\n"
" name: String::from(\"Peter\"),\n"
" age: 27,\n"
" };\n"
" peter.say_hello();\n"
"}\n"
"```"
#: src/methods.md:31
msgid "It can be helpful to introduce methods by comparing them to functions."
msgstr "메서드를 함수와 비교하여 소개하는 것도 도움이 될 수 있습니다."
#: src/methods.md:32
msgid ""
"Methods are called on an instance of a type (such as a struct or enum), the "
"first parameter represents the instance as `self`."
msgstr ""
"메서드는 구조체나 열거형과 같은 타입의 인스턴스에서 호출 되며, 첫번째 매개변"
"수(파라메터)는 인스턴스를 `self`로 표기합니다."
#: src/methods.md:33
msgid ""
"Developers may choose to use methods to take advantage of method receiver "
"syntax and to help keep them more organized. By using methods we can keep "
"all the implementation code in one predictable place."
msgstr ""
"메서드를 이용하면 receiver 문법을 사용할 수 있고 코드를 좀더 체계적으로 정리"
"할 수 있습니다. 메서드들이 예측 가능한 위치에 모여 있으니 찾기 쉽습니다."
#: src/methods.md:34
msgid "Point out the use of the keyword `self`, a method receiver."
msgstr "메서드 receiver인 `self` 키워드 사용을 언급해 주시기 바랍니다."
#: src/methods.md:35
msgid ""
"Show that it is an abbreviated term for `self: Self` and perhaps show how "
"the struct name could also be used."
msgstr ""
"예제의 경우 `self: &Self`의 줄인 버전임을 알려주고, 구조체의 이름을 직접 사용"
"하면 어떻게 되는지 보여주는 것도 좋습니다."
#: src/methods.md:36
msgid ""
"Explain that `Self` is a type alias for the type the `impl` block is in and "
"can be used elsewhere in the block."
msgstr ""
"`impl` 블록 내부에서는 `Self`가 해당 타입의 이름 대용으로 사용될 수 있음을 알"
"려주세요."
#: src/methods.md:37
msgid ""
"Note how `self` is used like other structs and dot notation can be used to "
"refer to individual fields."
msgstr ""
"구조체의 필드를 접근할 때 점 표기를 사용하듯이 `self`에 점 표기를 사용하여 개"
"별 필드들을 접근할 수 있습니다."
#: src/methods.md:38
msgid ""
"This might be a good time to demonstrate how the `&self` differs from `self` "
"by modifying the code and trying to run say_hello twice."
msgstr ""
"`say_hello` 함수가 두 번 호출되도록 코드를 수정하여 `&self`와 `self`가 어떻"
"게 다른지 보여주는 것도 좋습니다."
#: src/methods.md:39
msgid "We describe the distinction between method receivers next."
msgstr "다음 슬라이드에서 receiver의 구분을 설명합니다."
#: src/methods/receiver.md:3
msgid ""
"The `&self` above indicates that the method borrows the object immutably. "
"There are other possible receivers for a method:"
msgstr ""
"`&self`는 메서드가 객체를 불변하게 빌려옴을 나타냅니다. 메서드의 리시버는 다"
"음의 형태들이 가능합니다:"
#: src/methods/receiver.md:6
msgid ""
"`&self`: borrows the object from the caller using a shared and immutable "
"reference. The object can be used again afterwards."
msgstr ""
"`&self`: 호출자로부터 공유가능한 불변 참조 방식으로 객체를 빌려옴을 나타냅니"
"다. 객체는 메소드 호출 뒤에도 사용될 수 있습니다."
#: src/methods/receiver.md:8
msgid ""
"`&mut self`: borrows the object from the caller using a unique and mutable "
"reference. The object can be used again afterwards."
msgstr ""
"`&mut self`: 호출자로부터 유일한 가변 참조 방식으로 객체를 빌려옴을 나타냅니"
"다. 객체는 메소드 호출 뒤에도 사용될 수 있습니다."
#: src/methods/receiver.md:10
msgid ""
"`self`: takes ownership of the object and moves it away from the caller. The "
"method becomes the owner of the object. The object will be dropped "
"(deallocated) when the method returns, unless its ownership is explicitly "
"transmitted. Complete ownership does not automatically mean mutability."
msgstr ""
"`self`: 호출자로부터 객체의 소유권을 가져오고 객체는 호출자로부터 메소드로 이"
"동됩니다. 메소드가 객체를 소유하게 되며 따라서 명시적으로 소유권을 다른 곳으"
"로 전달하지 않는다면 메서드 종료와 함께 객체는 drop(해제)됩니다."
#: src/methods/receiver.md:14
msgid "`mut self`: same as above, but the method can mutate the object. "
msgstr ""
"`mut self`: 위와 동일하지만 메서드가 객체의 소유권을 가지면서 동시에 객체를 "
"수정할 수도 있습니다. 소유권을 가지는 것이 수정할 수 있음을 의미하는 것은 아"
"닙니다. "
#: src/methods/receiver.md:15
msgid ""
"No receiver: this becomes a static method on the struct. Typically used to "
"create constructors which are called `new` by convention."
msgstr ""
"리시버 없음: 구조체의 정적 메서드가 됩니다. 주로 생성자를 만들때 사용하게 되"
"며, 생성자는 흔히 `new`라고 이름붙입니다."
#: src/methods/receiver.md:18
msgid ""
"Beyond variants on `self`, there are also [special wrapper types](https://"
"doc.rust-lang.org/reference/special-types-and-traits.html) allowed to be "
"receiver types, such as `Box<Self>`."
msgstr ""
"`self`를 사용하는 이같은 변형들 외에도 `Box<Self>`와 같이 리시버 타입으로 허"
"용되는 [특별한 래퍼 타입](https://doc.rust-lang.org/reference/special-types-"
"and-traits.html)이 있습니다."
#: src/methods/receiver.md:24
msgid ""
"Consider emphasizing \"shared and immutable\" and \"unique and mutable\". "
"These constraints always come together in Rust due to borrow checker rules, "
"and `self` is no exception. It isn't possible to reference a struct from "
"multiple locations and call a mutating (`&mut self`) method on it."
msgstr ""
"\"공유가능한 불변\"과 \"유일한 가변\" 부분은 강조할 만합니다. 이러한 제약은 "
"러스트의 빌림 검사기(borrow checker) 규칙으로 늘 붙어다닙니다. `self`도 예외"
"는 아닙니다. 여러 위치에서 구조체를 참조하면서 객체를 수정하는(`&mut self`를 "
"리시버로 하는) 메서드를 호출하는 것은 불가능합니다."
#: src/methods/example.md:3
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Race {\n"
" name: String,\n"
" laps: Vec<i32>,\n"
"}\n"
"\n"
"impl Race {\n"
" fn new(name: &str) -> Race { // No receiver, a static method\n"
" Race { name: String::from(name), laps: Vec::new() }\n"
" }\n"
"\n"
" fn add_lap(&mut self, lap: i32) { // Exclusive borrowed read-write "
"access to self\n"
" self.laps.push(lap);\n"
" }\n"
"\n"
" fn print_laps(&self) { // Shared and read-only borrowed access to self\n"
" println!(\"Recorded {} laps for {}:\", self.laps.len(), self.name);\n"
" for (idx, lap) in self.laps.iter().enumerate() {\n"
" println!(\"Lap {idx}: {lap} sec\");\n"
" }\n"
" }\n"
"\n"
" fn finish(self) { // Exclusive ownership of self\n"
" let total = self.laps.iter().sum::<i32>();\n"
" println!(\"Race {} is finished, total lap time: {}\", self.name, "
"total);\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let mut race = Race::new(\"Monaco Grand Prix\");\n"
" race.add_lap(70);\n"
" race.add_lap(68);\n"
" race.print_laps();\n"
" race.add_lap(71);\n"
" race.print_laps();\n"
" race.finish();\n"
" // race.add_lap(42);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Race {\n"
" name: String,\n"
" laps: Vec<i32>,\n"
"}\n"
"\n"
"impl Race {\n"
" fn new(name: &str) -> Race { // No receiver, a static method\n"
" Race { name: String::from(name), laps: Vec::new() }\n"
" }\n"
"\n"
" fn add_lap(&mut self, lap: i32) { // Exclusive borrowed read-write "
"access to self\n"
" self.laps.push(lap);\n"
" }\n"
"\n"
" fn print_laps(&self) { // Shared and read-only borrowed access to self\n"
" println!(\"Recorded {} laps for {}:\", self.laps.len(), self.name);\n"
" for (idx, lap) in self.laps.iter().enumerate() {\n"
" println!(\"Lap {idx}: {lap} sec\");\n"
" }\n"
" }\n"
"\n"
" fn finish(self) { // Exclusive ownership of self\n"
" let total = self.laps.iter().sum::<i32>();\n"
" println!(\"Race {} is finished, total lap time: {}\", self.name, "
"total);\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let mut race = Race::new(\"Monaco Grand Prix\");\n"
" race.add_lap(70);\n"
" race.add_lap(68);\n"
" race.print_laps();\n"
" race.add_lap(71);\n"
" race.print_laps();\n"
" race.finish();\n"
" // race.add_lap(42);\n"
"}\n"
"```"
#: src/methods/example.md:47
msgid "All four methods here use a different method receiver."
msgstr "이 네 개의 메서드는 서로 다른 유형의 리시버를 사용합니다."
#: src/methods/example.md:48
msgid ""
"You can point out how that changes what the function can do with the "
"variable values and if/how it can be used again in `main`."
msgstr ""
"리시버의 유형에 따라 함수가 할 수 있는 일이 달라지고, 또 메소드를 호출한 뒤 "
"`main`에서 해당 객체를 사용할 수 있는지 여부도 달라진다는 점을 강조하세요."
#: src/methods/example.md:49
msgid ""
"You can showcase the error that appears when trying to call `finish` twice."
msgstr "`finish`를 두번 호출하여 오류가 발생하는 것을 보일 수 있습니다."
#: src/methods/example.md:50
msgid ""
"Note that although the method receivers are different, the non-static "
"functions are called the same way in the main body. Rust enables automatic "
"referencing and dereferencing when calling methods. Rust automatically adds "
"in the `&`, `*`, `muts` so that that object matches the method signature."
msgstr ""
"비록 메서드 receiver는 다르지만 main 함수에서 비 정적 함수를 부르는 방법은 같"
"습니다. 러스트는 메서드를 호출할 때 자동으로 참조/역참조(따라가기)를 수행합니"
"다. 러스트는 객체와 매서드 시그니처가 서로 매치되도록 객체에 `&`, `*`, `muts`"
"를 자동으로 붙여줍니다."
#: src/methods/example.md:51
msgid ""
"You might point out that `print_laps` is using a vector that is iterated "
"over. We describe vectors in more detail in the afternoon. "
msgstr ""
"`print_laps`함수에서 벡터를 어떤 식으로 사용하고 있는지 언급하는 것도 좋습니"
"다. 벡터는 오후 강의에서 더 자세히 설명할 것입니다. "
#: src/pattern-matching.md:3
msgid ""
"The `match` keyword let you match a value against one or more _patterns_. "
"The comparisons are done from top to bottom and the first match wins."
msgstr ""
"`match`키워드는 값을 여러 형태의 패턴과 매치시킬 수 있습니다. 맨 위 패턴부터 "
"하나씩 매치되는지 검사하며, 처음으로 매치되는 패턴이 선택됩니다."
#: src/pattern-matching.md:6
msgid "The patterns can be simple values, similarly to `switch` in C and C++:"
msgstr "C/C++의 `switch`와 비슷하게 값을 패턴으로 사용할 수도 있습니다:"
#: src/pattern-matching.md:8
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let input = 'x';\n"
"\n"
" match input {\n"
" 'q' => println!(\"Quitting\"),\n"
" 'a' | 's' | 'w' | 'd' => println!(\"Moving around\"),\n"
" '0'..='9' => println!(\"Number input\"),\n"
" _ => println!(\"Something else\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let input = 'x';\n"
"\n"
" match input {\n"
" 'q' => println!(\"Quitting\"),\n"
" 'a' | 's' | 'w' | 'd' => println!(\"Moving around\"),\n"
" '0'..='9' => println!(\"Number input\"),\n"
" _ => println!(\"Something else\"),\n"
" }\n"
"}\n"
"```"
#: src/pattern-matching.md:21
msgid "The `_` pattern is a wildcard pattern which matches any value."
msgstr "`_`패턴은 어떤 값과도 매칭되는 와일드카드입니다."
#: src/pattern-matching.md:26
msgid ""
"You might point out how some specific characters are being used when in a "
"pattern"
msgstr "패턴에서 사용되는 특수 문자들을 알려주세요"
#: src/pattern-matching.md:27
msgid "`|` as an `or`"
msgstr "`|`: or 기호입니다"
#: src/pattern-matching.md:28
msgid "`..` can expand as much as it needs to be"
msgstr "`..`: 필요한 만큼 확장합니다"
#: src/pattern-matching.md:29
msgid "`1..=5` represents an inclusive range"
msgstr "`1..=5`: 끝 값(여기서는 5)을 포함하는 범위를 나타냅니다"
#: src/pattern-matching.md:30
msgid "`_` is a wild card"
msgstr "`_`: 와일드카드입니다"
#: src/pattern-matching.md:31
msgid ""
"It can be useful to show how binding works, by for instance replacing a "
"wildcard character with a variable, or removing the quotes around `q`."
msgstr ""
"와일드카드 문자를 변수로 바꾸거나 `q`의 따옴표를 제거하는 식으로 수정하면서 "
"바인딩이 어떻게 작동하는지 보여주는 것도 유용할 수 있습니다."
#: src/pattern-matching.md:32
msgid "You can demonstrate matching on a reference."
msgstr "참조를 매칭하는 것도 시연할 수 있습니다."
#: src/pattern-matching.md:33
msgid ""
"This might be a good time to bring up the concept of irrefutable patterns, "
"as the term can show up in error messages."
msgstr ""
"에러 메시지에 \"반박 불가능 패턴(irrefutable pattern)\"이란 용어가 등장하기"
"도 합니다. 지금 그 의미를 소개하는 것도 좋을 것 같습니다."
#: src/pattern-matching/destructuring-enums.md:3
msgid ""
"Patterns can also be used to bind variables to parts of your values. This is "
"how you inspect the structure of your types. Let us start with a simple "
"`enum` type:"
msgstr ""
"구조체나 열거형 값의 일부를 패턴 매치를 통해 변수에 바인딩할 수 있습니다. 간"
"단한 `enum` 타입을 먼저 살펴보겠습니다:"
#: src/pattern-matching/destructuring-enums.md:6
msgid ""
"```rust,editable\n"
"enum Result {\n"
" Ok(i32),\n"
" Err(String),\n"
"}\n"
"\n"
"fn divide_in_two(n: i32) -> Result {\n"
" if n % 2 == 0 {\n"
" Result::Ok(n / 2)\n"
" } else {\n"
" Result::Err(format!(\"cannot divide {n} into two equal parts\"))\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let n = 100;\n"
" match divide_in_two(n) {\n"
" Result::Ok(half) => println!(\"{n} divided in two is {half}\"),\n"
" Result::Err(msg) => println!(\"sorry, an error happened: {msg}\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"enum Result {\n"
" Ok(i32),\n"
" Err(String),\n"
"}\n"
"\n"
"fn divide_in_two(n: i32) -> Result {\n"
" if n % 2 == 0 {\n"
" Result::Ok(n / 2)\n"
" } else {\n"
" Result::Err(format!(\"cannot divide {n} into two equal parts\"))\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let n = 100;\n"
" match divide_in_two(n) {\n"
" Result::Ok(half) => println!(\"{n} divided in two is {half}\"),\n"
" Result::Err(msg) => println!(\"sorry, an error happened: {msg}\"),\n"
" }\n"
"}\n"
"```"
#: src/pattern-matching/destructuring-enums.md:29
msgid ""
"Here we have used the arms to _destructure_ the `Result` value. In the first "
"arm, `half` is bound to the value inside the `Ok` variant. In the second "
"arm, `msg` is bound to the error message."
msgstr ""
"`match`구문에서 `divide_in_two`함수에서 반환되는 `Result` 값을 두 개의 팔(혹"
"은 가지)로 _분해(destructure)_ 하였습니다. 첫번째 팔에서 `half`는 `Ok` "
"variant에 담긴 값으로 바인딩됩니다. 두번째 팔에서 `msg`는 오류 메시지 문자열"
"에 바인딩됩니다."
#: src/pattern-matching/destructuring-enums.md:36
msgid ""
"The `if`/`else` expression is returning an enum that is later unpacked with "
"a `match`."
msgstr ""
"`if`/`else` 표현식은 열거형을 반환하고, 이 값은 나중에 `match`로 분해됩니다."
#: src/pattern-matching/destructuring-enums.md:37
msgid ""
"You can try adding a third variant to the enum definition and displaying the "
"errors when running the code. Point out the places where your code is now "
"inexhaustive and how the compiler tries to give you hints."
msgstr ""
"열거형에 세번째 variant를 추가하고 코드를 실행하여 오류를 표시해보세요. 코드 "
"어느 부분에 누락이 있는지, 그리고 컴파일러가 어떤 식으로 힌트를 주는지 같이 "
"살펴보세요."
#: src/pattern-matching/destructuring-structs.md:3
msgid "You can also destructure `structs`:"
msgstr "`struct` 구조체 역시 분해할 수 있습니다:"
#: src/pattern-matching/destructuring-structs.md:5
msgid ""
"```rust,editable\n"
"struct Foo {\n"
" x: (u32, u32),\n"
" y: u32,\n"
"}\n"
"\n"
"#[rustfmt::skip]\n"
"fn main() {\n"
" let foo = Foo { x: (1, 2), y: 3 };\n"
" match foo {\n"
" Foo { x: (1, b), y } => println!(\"x.0 = 1, b = {b}, y = {y}\"),\n"
" Foo { y: 2, x: i } => println!(\"y = 2, x = {i:?}\"),\n"
" Foo { y, .. } => println!(\"y = {y}, other fields were "
"ignored\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"struct Foo {\n"
" x: (u32, u32),\n"
" y: u32,\n"
"}\n"
"\n"
"#[rustfmt::skip]\n"
"fn main() {\n"
" let foo = Foo { x: (1, 2), y: 3 };\n"
" match foo {\n"
" Foo { x: (1, b), y } => println!(\"x.0 = 1, b = {b}, y = {y}\"),\n"
" Foo { y: 2, x: i } => println!(\"y = 2, x = {i:?}\"),\n"
" Foo { y, .. } => println!(\"y = {y}, other fields were "
"ignored\"),\n"
" }\n"
"}\n"
"```"
#: src/pattern-matching/destructuring-structs.md:23
msgid "Change the literal values in `foo` to match with the other patterns."
msgstr "`foo`의 리터럴 값을 다른 패턴과 일치하도록 변경합니다."
#: src/pattern-matching/destructuring-structs.md:24
msgid "Add a new field to `Foo` and make changes to the pattern as needed."
msgstr "`Foo`에 새 필드를 추가하고 필요에 따라 패턴을 변경합니다."
#: src/pattern-matching/destructuring-structs.md:25
msgid ""
"The distinction between a capture and a constant expression can be hard to "
"spot. Try changing the `2` in the second arm to a variable, and see that it "
"subtly doesn't work. Change it to a `const` and see it working again."
msgstr ""
"캡처와 상수 표현식은 구분하기 어려울 수 있습니다. 두 번째 부문의 `2`를 변수"
"로 변경해 보고 작동하지 않는 것을 확인하세요. `const`로 변경하고 다시 작동하"
"는지 확인합니다."
#: src/pattern-matching/destructuring-arrays.md:3
msgid ""
"You can destructure arrays, tuples, and slices by matching on their elements:"
msgstr ""
"배열이나 튜플, 슬라이스도 그 요소들에 대해 패턴 매칭으로 분해할 수 있습니다:"
#: src/pattern-matching/destructuring-arrays.md:5
msgid ""
"```rust,editable\n"
"#[rustfmt::skip]\n"
"fn main() {\n"
" let triple = [0, -2, 3];\n"
" println!(\"Tell me about {triple:?}\");\n"
" match triple {\n"
" [0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n"
" [1, ..] => println!(\"First is 1 and the rest were ignored\"),\n"
" _ => println!(\"All elements were ignored\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[rustfmt::skip]\n"
"fn main() {\n"
" let triple = [0, -2, 3];\n"
" println!(\"Tell me about {triple:?}\");\n"
" match triple {\n"
" [0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n"
" [1, ..] => println!(\"First is 1 and the rest were ignored\"),\n"
" _ => println!(\"All elements were ignored\"),\n"
" }\n"
"}\n"
"```"
#: src/pattern-matching/destructuring-arrays.md:21
msgid ""
"Destructuring of slices of unknown length also works with patterns of fixed "
"length."
msgstr ""
"길이를 알 수 없는 슬라이스에 대해서도 고정 길이 패턴으로 분해할 수 있습니다."
#: src/pattern-matching/destructuring-arrays.md:24
msgid ""
"```rust,editable\n"
"fn main() {\n"
" inspect(&[0, -2, 3]);\n"
" inspect(&[0, -2, 3, 4]);\n"
"}\n"
"\n"
"#[rustfmt::skip]\n"
"fn inspect(slice: &[i32]) {\n"
" println!(\"Tell me about {slice:?}\");\n"
" match slice {\n"
" &[0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n"
" &[1, ..] => println!(\"First is 1 and the rest were ignored\"),\n"
" _ => println!(\"All elements were ignored\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" inspect(&[0, -2, 3]);\n"
" inspect(&[0, -2, 3, 4]);\n"
"}\n"
"\n"
"#[rustfmt::skip]\n"
"fn inspect(slice: &[i32]) {\n"
" println!(\"Tell me about {slice:?}\");\n"
" match slice {\n"
" &[0, y, z] => println!(\"First is 0, y = {y}, and z = {z}\"),\n"
" &[1, ..] => println!(\"First is 1 and the rest were ignored\"),\n"
" _ => println!(\"All elements were ignored\"),\n"
" }\n"
"}\n"
"```"
#: src/pattern-matching/destructuring-arrays.md:41
msgid "Create a new pattern using `_` to represent an element. "
msgstr "`_`를 사용하여 요소를 매칭하는 패턴을 추가해보세요. "
#: src/pattern-matching/destructuring-arrays.md:42
msgid "Add more values to the array."
msgstr "배열에 값을 더 추가해보세요."
#: src/pattern-matching/destructuring-arrays.md:43
msgid ""
"Point out that how `..` will expand to account for different number of "
"elements."
msgstr "`..`가 요소 개수에 상관없이 매치될 수 있음을 알려주세요."
#: src/pattern-matching/destructuring-arrays.md:44
msgid "Show matching against the tail with patterns `[.., b]` and `[a@..,b]`"
msgstr ""
"`[.., b]`나 `[a@.., b]`와 같은 패턴으로 꼬리 부분을 매칭하는 것을 보여주세요"
#: src/pattern-matching/match-guards.md:3
msgid ""
"When matching, you can add a _guard_ to a pattern. This is an arbitrary "
"Boolean expression which will be executed if the pattern matches:"
msgstr ""
"패턴 뒤에 가드(guard, 조건식)를 덧붙일 수 있습니다. 가드는 패턴이 매치되면 추"
"가로 따져보는 불리언 표현식입니다:"
#: src/pattern-matching/match-guards.md:6
msgid ""
"```rust,editable\n"
"#[rustfmt::skip]\n"
"fn main() {\n"
" let pair = (2, -2);\n"
" println!(\"Tell me about {pair:?}\");\n"
" match pair {\n"
" (x, y) if x == y => println!(\"These are twins\"),\n"
" (x, y) if x + y == 0 => println!(\"Antimatter, kaboom!\"),\n"
" (x, _) if x % 2 == 1 => println!(\"The first one is odd\"),\n"
" _ => println!(\"No correlation...\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[rustfmt::skip]\n"
"fn main() {\n"
" let pair = (2, -2);\n"
" println!(\"Tell me about {pair:?}\");\n"
" match pair {\n"
" (x, y) if x == y => println!(\"These are twins\"),\n"
" (x, y) if x + y == 0 => println!(\"Antimatter, kaboom!\"),\n"
" (x, _) if x % 2 == 1 => println!(\"The first one is odd\"),\n"
" _ => println!(\"No correlation...\"),\n"
" }\n"
"}\n"
"```"
#: src/pattern-matching/match-guards.md:23
msgid ""
"Match guards as a separate syntax feature are important and necessary when "
"we wish to concisely express more complex ideas than patterns alone would "
"allow."
msgstr ""
"매치 가드는 별도의 문법 요소로서 패턴 자체만으로 표현하기 어려운 복잡한 경우"
"를 간결하게 표현하고자 할 때 유용합니다."
#: src/pattern-matching/match-guards.md:24
msgid ""
"They are not the same as separate `if` expression inside of the match arm. "
"An `if` expression inside of the branch block (after `=>`) happens after the "
"match arm is selected. Failing the `if` condition inside of that block won't "
"result in other arms of the original `match` expression being considered."
msgstr ""
"매치의 각 팔(혹은 가지) 안에 따로 `if`를 사용한 것과 다릅니다. 매치 가지의 "
"`=>` 뒤에 사용된 `if` 표현식은 해당 가지가 선택된 다음에 실행됩니다. 따라서 "
"여기서 `if` 조건이 실패하더라도 원래 `match`의 다른 가지는 고려되지 않습니다."
#: src/pattern-matching/match-guards.md:26
msgid "You can use the variables defined in the pattern in your if expression."
msgstr "패턴에 정의된 변수를 가드의 표현식에서 사용할 수 있습니다."
#: src/pattern-matching/match-guards.md:27
msgid ""
"The condition defined in the guard applies to every expression in a pattern "
"with an `|`."
msgstr "가드에 정의된 조건은 `|` 를 포함하는 패턴의 모든 표현식에 적용됩니다."
#: src/exercises/day-2/morning.md:1
msgid "Day 2: Morning Exercises"
msgstr "2일차 오전 연습문제"
#: src/exercises/day-2/morning.md:3
msgid "We will look at implementing methods in two contexts:"
msgstr "이번 연습문제들은 두가지 맥락에서 메서드 구현방법을 다룹니다:"
#: src/exercises/day-2/morning.md:5
msgid "Simple struct which tracks health statistics."
msgstr "건강 상태 통계를 추적하는 프로그램의 간단한 구조체."
#: src/exercises/day-2/morning.md:7
msgid "Multiple structs and enums for a drawing library."
msgstr "드로잉 라이브러리를 위한 구조체 및 열거헝."
#: src/exercises/day-2/health-statistics.md:3
msgid ""
"You're working on implementing a health-monitoring system. As part of that, "
"you need to keep track of users' health statistics."
msgstr ""
"당신은 건강 상태를 모니터링하는 시스템을 구현하는 일을 하고 있습니다. 그 일환"
"으로 당신은 사용자의 건강 상태 통계를 추적해야합니다."
#: src/exercises/day-2/health-statistics.md:6
msgid ""
"You'll start with some stubbed functions in an `impl` block as well as a "
"`User` struct definition. Your goal is to implement the stubbed out methods "
"on the `User` `struct` defined in the `impl` block."
msgstr ""
"당신의 목표는 `User` 구조체의 `impl` 블록의 빈 함수를 구현하는 것입니다."
#: src/exercises/day-2/health-statistics.md:10
msgid ""
"Copy the code below to <https://play.rust-lang.org/> and fill in the missing "
"methods:"
msgstr ""
"아래 코드를 <https://play.rust-lang.org/>에 복사해서 빠진 메서드를 구현하면 "
"됩니다:"
#: src/exercises/day-2/health-statistics.md:13
msgid ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub struct User {\n"
" name: String,\n"
" age: u32,\n"
" height: f32,\n"
" visit_count: usize,\n"
" last_blood_pressure: Option<(u32, u32)>,\n"
"}\n"
"\n"
"pub struct Measurements {\n"
" height: f32,\n"
" blood_pressure: (u32, u32),\n"
"}\n"
"\n"
"pub struct HealthReport<'a> {\n"
" patient_name: &'a str,\n"
" visit_count: u32,\n"
" height_change: f32,\n"
" blood_pressure_change: Option<(i32, i32)>,\n"
"}\n"
"\n"
"impl User {\n"
" pub fn new(name: String, age: u32, height: f32) -> Self {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn name(&self) -> &str {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn age(&self) -> u32 {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn height(&self) -> f32 {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn doctor_visits(&self) -> u32 {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn set_age(&mut self, new_age: u32) {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn set_height(&mut self, new_height: f32) {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn visit_doctor(&mut self, measurements: Measurements) -> "
"HealthReport {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" println!(\"I'm {} and my age is {}\", bob.name(), bob.age());\n"
"}\n"
"\n"
"#[test]\n"
"fn test_height() {\n"
" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" assert_eq!(bob.height(), 155.2);\n"
"}\n"
"\n"
"#[test]\n"
"fn test_set_age() {\n"
" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" assert_eq!(bob.age(), 32);\n"
" bob.set_age(33);\n"
" assert_eq!(bob.age(), 33);\n"
"}\n"
"\n"
"#[test]\n"
"fn test_visit() {\n"
" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" assert_eq!(bob.doctor_visits(), 0);\n"
" let report = bob.visit_doctor(Measurements {\n"
" height: 156.1,\n"
" blood_pressure: (120, 80),\n"
" });\n"
" assert_eq!(report.patient_name, \"Bob\");\n"
" assert_eq!(report.visit_count, 1);\n"
" assert_eq!(report.blood_pressure_change, None);\n"
"\n"
" let report = bob.visit_doctor(Measurements {\n"
" height: 156.1,\n"
" blood_pressure: (115, 76),\n"
" });\n"
"\n"
" assert_eq!(report.visit_count, 2);\n"
" assert_eq!(report.blood_pressure_change, Some((-5, -4)));\n"
"}\n"
"```"
msgstr ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub struct User {\n"
" name: String,\n"
" age: u32,\n"
" height: f32,\n"
" visit_count: usize,\n"
" last_blood_pressure: Option<(u32, u32)>,\n"
"}\n"
"\n"
"pub struct Measurements {\n"
" height: f32,\n"
" blood_pressure: (u32, u32),\n"
"}\n"
"\n"
"pub struct HealthReport<'a> {\n"
" patient_name: &'a str,\n"
" visit_count: u32,\n"
" height_change: f32,\n"
" blood_pressure_change: Option<(i32, i32)>,\n"
"}\n"
"\n"
"impl User {\n"
" pub fn new(name: String, age: u32, height: f32) -> Self {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn name(&self) -> &str {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn age(&self) -> u32 {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn height(&self) -> f32 {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn doctor_visits(&self) -> u32 {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn set_age(&mut self, new_age: u32) {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn set_height(&mut self, new_height: f32) {\n"
" unimplemented!()\n"
" }\n"
"\n"
" pub fn visit_doctor(&mut self, measurements: Measurements) -> "
"HealthReport {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" println!(\"I'm {} and my age is {}\", bob.name(), bob.age());\n"
"}\n"
"\n"
"#[test]\n"
"fn test_height() {\n"
" let bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" assert_eq!(bob.height(), 155.2);\n"
"}\n"
"\n"
"#[test]\n"
"fn test_set_age() {\n"
" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" assert_eq!(bob.age(), 32);\n"
" bob.set_age(33);\n"
" assert_eq!(bob.age(), 33);\n"
"}\n"
"\n"
"#[test]\n"
"fn test_visit() {\n"
" let mut bob = User::new(String::from(\"Bob\"), 32, 155.2);\n"
" assert_eq!(bob.doctor_visits(), 0);\n"
" let report = bob.visit_doctor(Measurements {\n"
" height: 156.1,\n"
" blood_pressure: (120, 80),\n"
" });\n"
" assert_eq!(report.patient_name, \"Bob\");\n"
" assert_eq!(report.visit_count, 1);\n"
" assert_eq!(report.blood_pressure_change, None);\n"
"\n"
" let report = bob.visit_doctor(Measurements {\n"
" height: 156.1,\n"
" blood_pressure: (115, 76),\n"
" });\n"
"\n"
" assert_eq!(report.visit_count, 2);\n"
" assert_eq!(report.blood_pressure_change, Some((-5, -4)));\n"
"}\n"
"```"
#: src/exercises/day-2/points-polygons.md:1
msgid "Polygon Struct"
msgstr "Polygon 구조체"
#: src/exercises/day-2/points-polygons.md:3
msgid ""
"We will create a `Polygon` struct which contain some points. Copy the code "
"below to <https://play.rust-lang.org/> and fill in the missing methods to "
"make the tests pass:"
msgstr ""
"우리는 몇개의 꼭지점을 가진 다각형을 표현하는 `Polygon` 구조체를 만들 것입니"
"다. 아래 코드를 <https://play.rust-lang.org/>에 복사해서 테스트가 통과하도록 "
"빠진 메서드를 구현하시면 됩니다:"
#: src/exercises/day-2/points-polygons.md:7
msgid ""
"```rust\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub struct Point {\n"
" // add fields\n"
"}\n"
"\n"
"impl Point {\n"
" // add methods\n"
"}\n"
"\n"
"pub struct Polygon {\n"
" // add fields\n"
"}\n"
"\n"
"impl Polygon {\n"
" // add methods\n"
"}\n"
"\n"
"pub struct Circle {\n"
" // add fields\n"
"}\n"
"\n"
"impl Circle {\n"
" // add methods\n"
"}\n"
"\n"
"pub enum Shape {\n"
" Polygon(Polygon),\n"
" Circle(Circle),\n"
"}\n"
"\n"
"#[cfg(test)]\n"
"mod tests {\n"
" use super::*;\n"
"\n"
" fn round_two_digits(x: f64) -> f64 {\n"
" (x * 100.0).round() / 100.0\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_magnitude() {\n"
" let p1 = Point::new(12, 13);\n"
" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_dist() {\n"
" let p1 = Point::new(10, 10);\n"
" let p2 = Point::new(14, 13);\n"
" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_add() {\n"
" let p1 = Point::new(16, 16);\n"
" let p2 = p1 + Point::new(-4, 3);\n"
" assert_eq!(p2, Point::new(12, 19));\n"
" }\n"
"\n"
" #[test]\n"
" fn test_polygon_left_most_point() {\n"
" let p1 = Point::new(12, 13);\n"
" let p2 = Point::new(16, 16);\n"
"\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(p1);\n"
" poly.add_point(p2);\n"
" assert_eq!(poly.left_most_point(), Some(p1));\n"
" }\n"
"\n"
" #[test]\n"
" fn test_polygon_iter() {\n"
" let p1 = Point::new(12, 13);\n"
" let p2 = Point::new(16, 16);\n"
"\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(p1);\n"
" poly.add_point(p2);\n"
"\n"
" let points = poly.iter().cloned().collect::<Vec<_>>();\n"
" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_shape_perimeters() {\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(Point::new(12, 13));\n"
" poly.add_point(Point::new(17, 11));\n"
" poly.add_point(Point::new(16, 16));\n"
" let shapes = vec![\n"
" Shape::from(poly),\n"
" Shape::from(Circle::new(Point::new(10, 20), 5)),\n"
" ];\n"
" let perimeters = shapes\n"
" .iter()\n"
" .map(Shape::perimeter)\n"
" .map(round_two_digits)\n"
" .collect::<Vec<_>>();\n"
" assert_eq!(perimeters, vec![15.48, 31.42]);\n"
" }\n"
"}\n"
"\n"
"#[allow(dead_code)]\n"
"fn main() {}\n"
"```"
msgstr ""
"```rust\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub struct Point {\n"
" // add fields\n"
"}\n"
"\n"
"impl Point {\n"
" // add methods\n"
"}\n"
"\n"
"pub struct Polygon {\n"
" // add fields\n"
"}\n"
"\n"
"impl Polygon {\n"
" // add methods\n"
"}\n"
"\n"
"pub struct Circle {\n"
" // add fields\n"
"}\n"
"\n"
"impl Circle {\n"
" // add methods\n"
"}\n"
"\n"
"pub enum Shape {\n"
" Polygon(Polygon),\n"
" Circle(Circle),\n"
"}\n"
"\n"
"#[cfg(test)]\n"
"mod tests {\n"
" use super::*;\n"
"\n"
" fn round_two_digits(x: f64) -> f64 {\n"
" (x * 100.0).round() / 100.0\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_magnitude() {\n"
" let p1 = Point::new(12, 13);\n"
" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_dist() {\n"
" let p1 = Point::new(10, 10);\n"
" let p2 = Point::new(14, 13);\n"
" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_add() {\n"
" let p1 = Point::new(16, 16);\n"
" let p2 = p1 + Point::new(-4, 3);\n"
" assert_eq!(p2, Point::new(12, 19));\n"
" }\n"
"\n"
" #[test]\n"
" fn test_polygon_left_most_point() {\n"
" let p1 = Point::new(12, 13);\n"
" let p2 = Point::new(16, 16);\n"
"\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(p1);\n"
" poly.add_point(p2);\n"
" assert_eq!(poly.left_most_point(), Some(p1));\n"
" }\n"
"\n"
" #[test]\n"
" fn test_polygon_iter() {\n"
" let p1 = Point::new(12, 13);\n"
" let p2 = Point::new(16, 16);\n"
"\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(p1);\n"
" poly.add_point(p2);\n"
"\n"
" let points = poly.iter().cloned().collect::<Vec<_>>();\n"
" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_shape_perimeters() {\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(Point::new(12, 13));\n"
" poly.add_point(Point::new(17, 11));\n"
" poly.add_point(Point::new(16, 16));\n"
" let shapes = vec![\n"
" Shape::from(poly),\n"
" Shape::from(Circle::new(Point::new(10, 20), 5)),\n"
" ];\n"
" let perimeters = shapes\n"
" .iter()\n"
" .map(Shape::perimeter)\n"
" .map(round_two_digits)\n"
" .collect::<Vec<_>>();\n"
" assert_eq!(perimeters, vec![15.48, 31.42]);\n"
" }\n"
"}\n"
"\n"
"#[allow(dead_code)]\n"
"fn main() {}\n"
"```"
#: src/exercises/day-2/points-polygons.md:117
msgid ""
"Since the method signatures are missing from the problem statements, the key "
"part of the exercise is to specify those correctly. You don't have to modify "
"the tests."
msgstr ""
"누락된 메서드 시그니처를 올바르게 정의하는 것이 문제의 핵심 부분입니다. 테스"
"트는 수정하면 안됩니다."
#: src/exercises/day-2/points-polygons.md:120
msgid "Other interesting parts of the exercise:"
msgstr "연습문제의 다른 흥미로운 부분:"
#: src/exercises/day-2/points-polygons.md:122
msgid ""
"Derive a `Copy` trait for some structs, as in tests the methods sometimes "
"don't borrow their arguments."
msgstr ""
"테스트 코드를 보면 어떤 메서드들은 인자를 borrow하는 대신 `Copy` 트레잇을 사"
"용하기도 합니다. 구조체가 `Copy` 트레잇을 상속(derive)하도록 하면 됩니다."
#: src/exercises/day-2/points-polygons.md:123
msgid ""
"Discover that `Add` trait must be implemented for two objects to be addable "
"via \"+\". Note that we do not discuss generics until Day 3."
msgstr ""
"\"+\"를 사용하여 두 객체를 서로 더하려면 `Add` 트레잇을 구현해야 합니다. 이"
"는 3일차에 다룰 내용입니다."
#: src/control-flow.md:3
msgid ""
"As we have seen, `if` is an expression in Rust. It is used to conditionally "
"evaluate one of two blocks, but the blocks can have a value which then "
"becomes the value of the `if` expression. Other control flow expressions "
"work similarly in Rust."
msgstr ""
"앞에서 살펴본 바와 같이 러스트에서 `if`는 표현식입니다. 조건에 따라 두 블록 "
"중 하나를 평가하며, 그 결과값이 `if` 표현식의 값이 됩니다. 다른 흐름제어 표현"
"식도 유사하게 작동합니다."
#: src/control-flow/blocks.md:3
msgid ""
"A block in Rust contains a sequence of expressions. Each block has a value "
"and a type, which are those of the last expression of the block:"
msgstr ""
"러스트에서 블록은 값과 타입을 갖습니다. 블록의 마지막 표현식이 블록의 값이 됩"
"니다:"
#: src/control-flow/blocks.md:7
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let x = {\n"
" let y = 10;\n"
" println!(\"y: {y}\");\n"
" let z = {\n"
" let w = {\n"
" 3 + 4\n"
" };\n"
" println!(\"w: {w}\");\n"
" y * w\n"
" };\n"
" println!(\"z: {z}\");\n"
" z - y\n"
" };\n"
" println!(\"x: {x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let x = {\n"
" let y = 10;\n"
" println!(\"y: {y}\");\n"
" let z = {\n"
" let w = {\n"
" 3 + 4\n"
" };\n"
" println!(\"w: {w}\");\n"
" y * w\n"
" };\n"
" println!(\"z: {z}\");\n"
" z - y\n"
" };\n"
" println!(\"x: {x}\");\n"
"}\n"
"```"
#: src/control-flow/blocks.md:26
msgid ""
"If the last expression ends with `;`, then the resulting value and type is "
"`()`."
msgstr ""
"위의 `main` 함수는 마지막 표현식이 `;`로 끝나기 때문에 반환되는 값과 타입이 "
"`()`입니다."
#: src/control-flow/blocks.md:28
msgid ""
"The same rule is used for functions: the value of the function body is the "
"return value:"
msgstr ""
"함수에도 동일한 규칙이 적용됩니다. 함수 바디를 이루는 블록의 값이 반환값이 됩"
"니다:"
#: src/control-flow/blocks.md:31
msgid ""
"```rust,editable\n"
"fn double(x: i32) -> i32 {\n"
" x + x\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"doubled: {}\", double(7));\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn double(x: i32) -> i32 {\n"
" x + x\n"
"}\n"
"\n"
"fn main() {\n"
" println!(\"doubled: {}\", double(7));\n"
"}\n"
"```"
#: src/control-flow/blocks.md:44
msgid ""
"The point of this slide is to show that blocks have a type and value in "
"Rust. "
msgstr ""
"러스트에서는 블록이 타입과 값을 가진다는 점이 이 슬라이드의 핵심입니다. "
#: src/control-flow/blocks.md:45
msgid ""
"You can show how the value of the block changes by changing the last line in "
"the block. For instance, adding/removing a semicolon or using a `return`."
msgstr ""
"블록 마지막 줄을 수정하면서 블록의 값이 어떻게 바뀌는지 보여주세요. 예를 들"
"어, 세미콜론을 넣거나 뺀다든지, 아니면 `return`을 사용해 보세요."
#: src/control-flow/if-expressions.md:1
msgid "`if` expressions"
msgstr "`if` 표현식"
#: src/control-flow/if-expressions.md:3
msgid ""
"You use [`if` expressions](https://doc.rust-lang.org/reference/expressions/"
"if-expr.html#if-expressions) exactly like `if` statements in other languages:"
msgstr ""
"다른 언어의 `if` 문과 똑같이 [`if` 표현식](https://doc.rust-lang.org/"
"reference/expressions/if-expr.html#if-expressions)을 사용합니다:"
#: src/control-flow/if-expressions.md:7
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" if x % 2 == 0 {\n"
" x = x / 2;\n"
" } else {\n"
" x = 3 * x + 1;\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" if x % 2 == 0 {\n"
" x = x / 2;\n"
" } else {\n"
" x = 3 * x + 1;\n"
" }\n"
"}\n"
"```"
#: src/control-flow/if-expressions.md:18
msgid ""
"In addition, you can use `if` as an expression. The last expression of each "
"block becomes the value of the `if` expression:"
msgstr ""
"게다가 `if`는 표현식으로 사용할 수도 있습니다. 아래 코드는 위와 동일합니다:"
#: src/control-flow/if-expressions.md:22
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" x = if x % 2 == 0 {\n"
" x / 2\n"
" } else {\n"
" 3 * x + 1\n"
" };\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" x = if x % 2 == 0 {\n"
" x / 2\n"
" } else {\n"
" 3 * x + 1\n"
" };\n"
"}\n"
"```"
#: src/control-flow/if-expressions.md:35
msgid ""
"Because `if` is an expression and must have a particular type, both of its "
"branch blocks must have the same type. Consider showing what happens if you "
"add `;` after `x / 2` in the second example."
msgstr ""
"`if`는 표현식이고 타입을 가져야 하므로 분기 블록은 모두 같은 타입을 가져야 합"
"니다. 두번째 예시의 `x / 2` 뒤에 `;`를 추가하여 어떻게 되는지 확인해 보시기 "
"바랍니다."
#: src/control-flow/if-let-expressions.md:1
msgid "`if let` expressions"
msgstr "`if let` 표현식"
#: src/control-flow/if-let-expressions.md:3
msgid ""
"The [`if let` expression](https://doc.rust-lang.org/reference/expressions/if-"
"expr.html#if-let-expressions) lets you execute different code depending on "
"whether a value matches a pattern:"
msgstr ""
"[`if let` 표현식](https://doc.rust-lang.org/reference/expressions/if-expr."
"html#if-let-expressions)을 사용하면 값이 패턴과 일치하는지에 따라 다른 코드"
"를 실행할 수 있습니다:"
#: src/control-flow/if-let-expressions.md:7
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let arg = std::env::args().next();\n"
" if let Some(value) = arg {\n"
" println!(\"Program name: {value}\");\n"
" } else {\n"
" println!(\"Missing name?\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let arg = std::env::args().next();\n"
" if let Some(value) = arg {\n"
" println!(\"Program name: {value}\");\n"
" } else {\n"
" println!(\"Missing name?\");\n"
" }\n"
"}\n"
"```"
#: src/control-flow/if-let-expressions.md:18
#: src/control-flow/while-let-expressions.md:21
#: src/control-flow/match-expressions.md:23
msgid ""
"See [pattern matching](../pattern-matching.md) for more details on patterns "
"in Rust."
msgstr "패턴에 관한 설명은 [패턴 매칭](../pattern-matching.md)을 참조하세요."
#: src/control-flow/if-let-expressions.md:23
msgid ""
"Unlike `match`, `if let` does not have to cover all branches. This can make "
"it more concise than `match`."
msgstr ""
"`if let`이 `match`보다 더 간결할 수 있습니다(예: 한가지 브랜치만 흥미로운 경"
"우). 이와 달리 `match`에서는 모든 브랜치가 처리되어야 합니다."
#: src/control-flow/if-let-expressions.md:24
msgid "A common usage is handling `Some` values when working with `Option`."
msgstr "일반적 사용법은 `Option`을 사용할 때 `Some` 값을 처리하는 것입니다."
#: src/control-flow/if-let-expressions.md:25
msgid ""
"Unlike `match`, `if let` does not support guard clauses for pattern matching."
msgstr ""
"`match`와 달리 `if let`은 패턴 일치를 위한 보호 절을 지원하지 않습니다."
#: src/control-flow/if-let-expressions.md:26
msgid ""
"Since 1.65, a similar [let-else](https://doc.rust-lang.org/rust-by-example/"
"flow_control/let_else.html) construct allows to do a destructuring "
"assignment, or if it fails, execute a block which is required to abort "
"normal control flow (with `panic`/`return`/`break`/`continue`):"
msgstr ""
"1.65부터 유사한 [let-else](https://doc.rust-lang.org/rust-by-example/"
"flow_control/let_else.html) 구성은 디스트럭처링 할당을 실행하거나 실패할 경"
"우 반환되지 않는 블록 브랜치(panic/return/break/continue)를 보유하도록 허용합"
"니다:"
#: src/control-flow/if-let-expressions.md:28
msgid ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"{:?}\", second_word_to_upper(\"foo bar\"));\n"
"}\n"
" \n"
"fn second_word_to_upper(s: &str) -> Option<String> {\n"
" let mut it = s.split(' ');\n"
" let (Some(_), Some(item)) = (it.next(), it.next()) else {\n"
" return None;\n"
" };\n"
" Some(item.to_uppercase())\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" println!(\"{:?}\", second_word_to_upper(\"foo bar\"));\n"
"}\n"
" \n"
"fn second_word_to_upper(s: &str) -> Option<String> {\n"
" let mut it = s.split(' ');\n"
" let (Some(_), Some(item)) = (it.next(), it.next()) else {\n"
" return None;\n"
" };\n"
" Some(item.to_uppercase())\n"
"}\n"
"```"
#: src/control-flow/while-expressions.md:1
msgid "`while` loops"
msgstr "`while` 반복문"
#: src/control-flow/while-expressions.md:3
msgid ""
"The [`while` keyword](https://doc.rust-lang.org/reference/expressions/loop-"
"expr.html#predicate-loops) works very similar to other languages:"
msgstr ""
"[`while` 키워드](https://doc.rust-lang.org/reference/expressions/loop-expr."
"html#predicate-loops)는 다른 언어와 매우 비슷하게 작동합니다:"
#: src/control-flow/while-expressions.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" while x != 1 {\n"
" x = if x % 2 == 0 {\n"
" x / 2\n"
" } else {\n"
" 3 * x + 1\n"
" };\n"
" }\n"
" println!(\"Final x: {x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" while x != 1 {\n"
" x = if x % 2 == 0 {\n"
" x / 2\n"
" } else {\n"
" 3 * x + 1\n"
" };\n"
" }\n"
" println!(\"Final x: {x}\");\n"
"}\n"
"```"
#: src/control-flow/while-let-expressions.md:1
msgid "`while let` loops"
msgstr "`while let` 반복문"
#: src/control-flow/while-let-expressions.md:3
msgid ""
"Like with `if let`, there is a [`while let`](https://doc.rust-lang.org/"
"reference/expressions/loop-expr.html#predicate-pattern-loops) variant which "
"repeatedly tests a value against a pattern:"
msgstr ""
"마지막으로, 무한 루프를 만드는 [`loop` 키워드](https://doc.rust-lang.org/"
"reference/expressions/loop-expr.html#infinite-loops)가 있습니다:"
#: src/control-flow/while-let-expressions.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" let mut iter = v.into_iter();\n"
"\n"
" while let Some(x) = iter.next() {\n"
" println!(\"x: {x}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" let mut iter = v.into_iter();\n"
"\n"
" while let Some(x) = iter.next() {\n"
" println!(\"x: {x}\");\n"
" }\n"
"}\n"
"```"
#: src/control-flow/while-let-expressions.md:17
msgid ""
"Here the iterator returned by `v.into_iter()` will return a `Option<i32>` on "
"every call to `next()`. It returns `Some(x)` until it is done, after which "
"it will return `None`. The `while let` lets us keep iterating through all "
"items."
msgstr ""
"`v.into_iter()`가 반환한 반복자는 `next()`가 호출될 때마다 `Option<i32>`를 반"
"환합니다. 반복자가 완료될 때까지는 `Some(x)`를 반환하고 마지막엔 `None`을 반"
"환합니다. `while let`을 통해 반복자의 모든 아이템을 확인할 수 있습니다."
#: src/control-flow/while-let-expressions.md:26
msgid ""
"Point out that the `while let` loop will keep going as long as the value "
"matches the pattern."
msgstr "`while let`은 값이 패턴에 매치되는 동안 계속됩니다."
#: src/control-flow/while-let-expressions.md:27
msgid ""
"You could rewrite the `while let` loop as an infinite loop with an if "
"statement that breaks when there is no value to unwrap for `iter.next()`. "
"The `while let` provides syntactic sugar for the above scenario."
msgstr ""
"`while let` 루프 대신 무한 루프를 사용하고 `iter.next()`가 빈 값을 반환할 때 "
"루프를 빠져나오도록 작성할수도 있습니다. `while let`은 그러한 경우를 위한 문"
"법적 편의를 제공합니다."
#: src/control-flow/for-expressions.md:1
msgid "`for` loops"
msgstr "`for` 반복문"
#: src/control-flow/for-expressions.md:3
msgid ""
"The [`for` loop](https://doc.rust-lang.org/std/keyword.for.html) is closely "
"related to the [`while let` loop](while-let-expressions.md). It will "
"automatically call `into_iter()` on the expression and then iterate over it:"
msgstr ""
"`for` 반복문은 `while let` 반복문과 매우 유사합니다. `for` 반복문은 자동으로 "
"`into_iter()`를 호출한 다음 이를 반복합니다:"
#: src/control-flow/for-expressions.md:7
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
"\n"
" for x in v {\n"
" println!(\"x: {x}\");\n"
" }\n"
" \n"
" for i in (0..10).step_by(2) {\n"
" println!(\"i: {i}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
"\n"
" for x in v {\n"
" println!(\"x: {x}\");\n"
" }\n"
" \n"
" for i in (0..10).step_by(2) {\n"
" println!(\"i: {i}\");\n"
" }\n"
"}\n"
"```"
#: src/control-flow/for-expressions.md:21
msgid "You can use `break` and `continue` here as usual."
msgstr "다른 언어와 마찬가지로 `break` 와 `continue`를 사용할 수 있습니다."
#: src/control-flow/for-expressions.md:25
msgid "Index iteration is not a special syntax in Rust for just that case."
msgstr "러스트는 인덱스 기반의 반복을 위한 별도의 문법을 사용하지 않습니다."
#: src/control-flow/for-expressions.md:26
msgid "`(0..10)` is a range that implements an `Iterator` trait. "
msgstr "`(0..10)`은 `Iterator` 트레잇을 구현하는 범위(range) 값입니다. "
#: src/control-flow/for-expressions.md:27
msgid ""
"`step_by` is a method that returns another `Iterator` that skips every other "
"element. "
msgstr ""
"`step_by`는 반복자의 요소들을 건너뛰는 또다른 `Iterator`를 반환하는 메서드입"
"니다. "
#: src/control-flow/for-expressions.md:28
msgid ""
"Modify the elements in the vector and explain the compiler errors. Change "
"vector `v` to be mutable and the for loop to `for x in v.iter_mut()`."
msgstr ""
"벡터 요소들을 수정하려고 하면 나오는 컴파일러 에러를 같이 살펴보세요. `v` 벡"
"터를 가변 변수로 변경하고 루프는 `for x in v.iter_mut()`로 수정하세요."
#: src/control-flow/loop-expressions.md:1
msgid "`loop` expressions"
msgstr "`loop` 표현식"
#: src/control-flow/loop-expressions.md:3
msgid ""
"Finally, there is a [`loop` keyword](https://doc.rust-lang.org/reference/"
"expressions/loop-expr.html#infinite-loops) which creates an endless loop."
msgstr ""
"마지막으로, 무한 루프를 만드는 [`loop` 키워드](https://doc.rust-lang.org/"
"reference/expressions/loop-expr.html#infinite-loops)가 있습니다."
#: src/control-flow/loop-expressions.md:6
msgid "Here you must either `break` or `return` to stop the loop:"
msgstr "따라서 반드시 `break` 또는 `return`을 사용해서 루프를 정지해야 합니다:"
#: src/control-flow/loop-expressions.md:8
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" loop {\n"
" x = if x % 2 == 0 {\n"
" x / 2\n"
" } else {\n"
" 3 * x + 1\n"
" };\n"
" if x == 1 {\n"
" break;\n"
" }\n"
" }\n"
" println!(\"Final x: {x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut x = 10;\n"
" loop {\n"
" x = if x % 2 == 0 {\n"
" x / 2\n"
" } else {\n"
" 3 * x + 1\n"
" };\n"
" if x == 1 {\n"
" break;\n"
" }\n"
" }\n"
" println!(\"Final x: {x}\");\n"
"}\n"
"```"
#: src/control-flow/loop-expressions.md:27
msgid "Break the `loop` with a value (e.g. `break 8`) and print it out."
msgstr "`loop`를 값(예: `break 8`)으로 나누고 출력합니다."
#: src/control-flow/loop-expressions.md:28
msgid ""
"Note that `loop` is the only looping construct which returns a non-trivial "
"value. This is because it's guaranteed to be entered at least once (unlike "
"`while` and `for` loops)."
msgstr ""
"`loop`는 non-trivial 값을 반환하는 유일한 반복문입니다. 이는 `while` 및 "
"`for` 반복문과 달리 최소한 한 번은 루프문을 수행하는 것이 보장되기 때문입니"
"다."
#: src/control-flow/match-expressions.md:1
msgid "`match` expressions"
msgstr "`match` 표현식"
#: src/control-flow/match-expressions.md:3
msgid ""
"The [`match` keyword](https://doc.rust-lang.org/reference/expressions/match-"
"expr.html) is used to match a value against one or more patterns. In that "
"sense, it works like a series of `if let` expressions:"
msgstr ""
"`match`키워드는 어떤 값을 하나 이상의 패턴에 대해 매치하는데 사용합니다. 그"
"런 면에서 `if let` 표현식을 여러개 이어 놓은 것과 같습니다:"
#: src/control-flow/match-expressions.md:7
msgid ""
"```rust,editable\n"
"fn main() {\n"
" match std::env::args().next().as_deref() {\n"
" Some(\"cat\") => println!(\"Will do cat things\"),\n"
" Some(\"ls\") => println!(\"Will ls some files\"),\n"
" Some(\"mv\") => println!(\"Let's move some files\"),\n"
" Some(\"rm\") => println!(\"Uh, dangerous!\"),\n"
" None => println!(\"Hmm, no program name?\"),\n"
" _ => println!(\"Unknown program name!\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" match std::env::args().next().as_deref() {\n"
" Some(\"cat\") => println!(\"Will do cat things\"),\n"
" Some(\"ls\") => println!(\"Will ls some files\"),\n"
" Some(\"mv\") => println!(\"Let's move some files\"),\n"
" Some(\"rm\") => println!(\"Uh, dangerous!\"),\n"
" None => println!(\"Hmm, no program name?\"),\n"
" _ => println!(\"Unknown program name!\"),\n"
" }\n"
"}\n"
"```"
#: src/control-flow/match-expressions.md:20
msgid ""
"Like `if let`, each match arm must have the same type. The type is the last "
"expression of the block, if any. In the example above, the type is `()`."
msgstr ""
"`if let`과 마찬가지로 매치의 모든 팔(arm)은 같은 타입이어야 합니다. 팔이 블록"
"이라면 블록의 마지막 표현식이 그 타입이 됩니다. 위의 예제에서 매치 표현식의 "
"타입은 `()`입니다."
#: src/control-flow/match-expressions.md:28
msgid "Save the match expression to a variable and print it out."
msgstr "`match` 표현식을 변수에 할당하고 그 값을 출력해보세요."
#: src/control-flow/match-expressions.md:29
msgid "Remove `.as_deref()` and explain the error."
msgstr "`.as_deref()`를 지워보고, 이 때 나오는 에러를 설명해주세요."
#: src/control-flow/match-expressions.md:30
msgid ""
"`std::env::args().next()` returns an `Option<String>`, but we cannot match "
"against `String`."
msgstr ""
"`std::env::args().next()`는 `Option<String>` 값을 반환하는데, `String`은 직"
"접 매치할 수 없습니다."
#: src/control-flow/match-expressions.md:31
msgid ""
"`as_deref()` transforms an `Option<T>` to `Option<&T::Target>`. In our case, "
"this turns `Option<String>` into `Option<&str>`."
msgstr ""
"`as_deref()`는 `Option<T>`를 `Option<&T::Target>`으로 바꿔줍니다. 이 경우는 "
"`Option<String>`에서 `Option<&str>`로 바뀝니다."
#: src/control-flow/match-expressions.md:32
msgid ""
"We can now use pattern matching to match against the `&str` inside `Option`."
msgstr "이제는 패턴 매칭으로 `Option` 안의 `&str`을 매치할 수 있습니다."
#: src/control-flow/break-continue.md:1
msgid "`break` and `continue`"
msgstr "`break`와 `continue`"
#: src/control-flow/break-continue.md:3
msgid ""
"If you want to exit a loop early, use [`break`](https://doc.rust-lang.org/"
"reference/expressions/loop-expr.html#break-expressions),"
msgstr ""
"루프를 조기에 종료하려면 [`break`](https://doc.rust-lang.org/reference/"
"expressions/loop-expr.html#break-expressions)를 사용합니다,"
#: src/control-flow/break-continue.md:4
msgid ""
"If you want to immediately start the next iteration use [`continue`](https://"
"doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)."
msgstr ""
"다음 반복을 즉시 시작하려면 [`continue`](https://doc.rust-lang.org/reference/"
"expressions/loop-expr.html#continue-expressions)를 사용합니다."
#: src/control-flow/break-continue.md:7
msgid ""
"Both `continue` and `break` can optionally take a label argument which is "
"used to break out of nested loops:"
msgstr ""
"루프를 빠져나가려면 `break`를, 다음 반복으로 넘어가기 위해서는 `continue`를 "
"사용합니다. 중첩 루프에서는 레이블과 함께 사용할 수 있습니다:"
#: src/control-flow/break-continue.md:10
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" let mut iter = v.into_iter();\n"
" 'outer: while let Some(x) = iter.next() {\n"
" println!(\"x: {x}\");\n"
" let mut i = 0;\n"
" while i < x {\n"
" println!(\"x: {x}, i: {i}\");\n"
" i += 1;\n"
" if i == 3 {\n"
" break 'outer;\n"
" }\n"
" }\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" let mut iter = v.into_iter();\n"
" 'outer: while let Some(x) = iter.next() {\n"
" println!(\"x: {x}\");\n"
" let mut i = 0;\n"
" while i < x {\n"
" println!(\"x: {x}, i: {i}\");\n"
" i += 1;\n"
" if i == 3 {\n"
" break 'outer;\n"
" }\n"
" }\n"
" }\n"
"}\n"
"```"
#: src/control-flow/break-continue.md:28
msgid ""
"In this case we break the outer loop after 3 iterations of the inner loop."
msgstr ""
"위 예제는 내부의 `while` 루프를 3회 반복한 후 바깥 루프를 빠져나갑니다."
#: src/std.md:3
msgid ""
"Rust comes with a standard library which helps establish a set of common "
"types used by Rust library and programs. This way, two libraries can work "
"together smoothly because they both use the same `String` type."
msgstr ""
"러스트에서 제공하는 표준 라이브러리는 러스트로 라이브러리나 프로그램을 작성"
"할 때 공통적으로 사용할 수 있는 여러 타입들을 포함하고 있습니다. 이를 통해 서"
"로 다른 두 라이브러리라 하더라도 함께 사용하는데 큰 어려움이 없게 됩니다. 예"
"를 들면 두 라이브러리 모두 같은 `String` 타입을 사용하기 때문입니다."
#: src/std.md:7
msgid "The common vocabulary types include:"
msgstr "일반적인 타입은 아래와 같습니다:"
#: src/std.md:9
msgid ""
"[`Option` and `Result`](std/option-result.md) types: used for optional "
"values and [error handling](error-handling.md)."
msgstr ""
"[`Option`과 `Result`](std/option-result.md) : 어떤 값이 있거나 없거나 하는 경"
"우, 그리고 [오류 처리](error-handling.md)에 사용합니다."
#: src/std.md:12
msgid "[`String`](std/string.md): the default string type used for owned data."
msgstr ""
"[`String`](std/string.md): 기본적인 문자열 타입으로, 문자열 데이터를 소유하"
"는 경우에 사용합니다."
#: src/std.md:14
msgid "[`Vec`](std/vec.md): a standard extensible vector."
msgstr "[`Vec`](std/vec.md): 가변 크기의 표준 벡터 타입입니다."
#: src/std.md:16
msgid ""
"[`HashMap`](std/hashmap.md): a hash map type with a configurable hashing "
"algorithm."
msgstr ""
"[`HashMap`](std/hashmap.md): 해시 알고리즘을 따로 지정할 수도 있는 해시맵 타"
"입입니다."
#: src/std.md:19
msgid "[`Box`](std/box.md): an owned pointer for heap-allocated data."
msgstr "[`Box`](std/box.md): 힙 데이터에 대한 소유 포인터입니다."
#: src/std.md:21
msgid ""
"[`Rc`](std/rc.md): a shared reference-counted pointer for heap-allocated "
"data."
msgstr ""
"[`Rc`](std/rc.md): 힙에 할당된 데이터에 대한 참조 카운팅 공유 포인터입니다."
#: src/std.md:25
msgid ""
"In fact, Rust contains several layers of the Standard Library: `core`, "
"`alloc` and `std`. "
msgstr ""
"사실, 러스트의 표준 라이브러리는 `core`, `alloc`, `std`와 같이 계층(layer)으"
"로 나눠집니다. "
#: src/std.md:26
msgid ""
"`core` includes the most basic types and functions that don't depend on "
"`libc`, allocator or even the presence of an operating system. "
msgstr ""
"`core`는 `libc`나 할당자(allocator), 심지어 OS에도 의존하지 않는 가장 기본적"
"인 함수와 타입을 포함합니다. "
#: src/std.md:28
msgid ""
"`alloc` includes types which require a global heap allocator, such as `Vec`, "
"`Box` and `Arc`."
msgstr ""
"`alloc`은 `Vec`, `Box`, `Arc`와 같이 전역 힙 할당이 필요한 타입을 포함합니다."
#: src/std.md:29
msgid ""
"Embedded Rust applications often only use `core`, and sometimes `alloc`."
msgstr ""
"임베디드 러스트 응용프로그램은 주로 `core`만 사용하거나 가끔 `alloc`을 함께 "
"사용합니다."
#: src/std/option-result.md:1
msgid "`Option` and `Result`"
msgstr "`Option`과 `Result`"
#: src/std/option-result.md:3
msgid "The types represent optional data:"
msgstr "이 타입은 선택적 데이터를 나타냅니다:"
#: src/std/option-result.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let numbers = vec![10, 20, 30];\n"
" let first: Option<&i8> = numbers.first();\n"
" println!(\"first: {first:?}\");\n"
"\n"
" let idx: Result<usize, usize> = numbers.binary_search(&10);\n"
" println!(\"idx: {idx:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let numbers = vec![10, 20, 30];\n"
" let first: Option<&i8> = numbers.first();\n"
" println!(\"first: {first:?}\");\n"
"\n"
" let idx: Result<usize, usize> = numbers.binary_search(&10);\n"
" println!(\"idx: {idx:?}\");\n"
"}\n"
"```"
#: src/std/option-result.md:18
msgid "`Option` and `Result` are widely used not just in the standard library."
msgstr ""
"`Option`과 `Result`는 표준 라이브러리뿐만아니라 매우 광범위하게 사용되는 타입"
"입니다."
#: src/std/option-result.md:19
msgid "`Option<&T>` has zero space overhead compared to `&T`."
msgstr "`Option<&T>` 는 `&T`에 비해 공간 오버헤드가 없습니다."
#: src/std/option-result.md:20
msgid ""
"`Result` is the standard type to implement error handling as we will see on "
"Day 3."
msgstr ""
"`Result`는 오류 처리를 위한 표준 타입입니다. 3일차 과정에서 살펴봅니다."
#: src/std/option-result.md:21
msgid "`binary_search` returns `Result<usize, usize>`."
msgstr "`binary_search`는 `Result<usize, usize>`를 반환합니다."
#: src/std/option-result.md:22
msgid "If found, `Result::Ok` holds the index where the element is found."
msgstr "요소가 발견된다면, `Result::Ok`는 발견된 요소의 인덱스를 보유합니다."
#: src/std/option-result.md:23
msgid ""
"Otherwise, `Result::Err` contains the index where such an element should be "
"inserted."
msgstr ""
"아니면, `Result::Err`에는 요소가 삽입되야 하는 인덱스가 포함되어 있습니다."
#: src/std/string.md:3
msgid ""
"[`String`](https://doc.rust-lang.org/std/string/struct.String.html) is the "
"standard heap-allocated growable UTF-8 string buffer:"
msgstr ""
"[`String`](https://doc.rust-lang.org/std/string/struct.String.html)은 힙에 할"
"당되고 가변 길이의 표준 UTF-8 문자열 버퍼입니다:"
#: src/std/string.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut s1 = String::new();\n"
" s1.push_str(\"Hello\");\n"
" println!(\"s1: len = {}, capacity = {}\", s1.len(), s1.capacity());\n"
"\n"
" let mut s2 = String::with_capacity(s1.len() + 1);\n"
" s2.push_str(&s1);\n"
" s2.push('!');\n"
" println!(\"s2: len = {}, capacity = {}\", s2.len(), s2.capacity());\n"
"\n"
" let s3 = String::from(\"🇨🇭\");\n"
" println!(\"s3: len = {}, number of chars = {}\", s3.len(),\n"
" s3.chars().count());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut s1 = String::new();\n"
" s1.push_str(\"Hello\");\n"
" println!(\"s1: len = {}, capacity = {}\", s1.len(), s1.capacity());\n"
"\n"
" let mut s2 = String::with_capacity(s1.len() + 1);\n"
" s2.push_str(&s1);\n"
" s2.push('!');\n"
" println!(\"s2: len = {}, capacity = {}\", s2.len(), s2.capacity());\n"
"\n"
" let s3 = String::from(\"🇨🇭\");\n"
" println!(\"s3: len = {}, number of chars = {}\", s3.len(),\n"
" s3.chars().count());\n"
"}\n"
"```"
#: src/std/string.md:22
msgid ""
"`String` implements [`Deref<Target = str>`](https://doc.rust-lang.org/std/"
"string/struct.String.html#deref-methods-str), which means that you can call "
"all `str` methods on a `String`."
msgstr ""
"`String`은 [`Deref<Target = str>`](https://doc.rust-lang.org/std/string/"
"struct.String.html#deref-methods-str)을 구현합니다. 이는 , `String` 값에 대해"
"서도 `str`의 모든 메서드를 호출 할 수 있다는 의미 입니다."
#: src/std/string.md:30
msgid ""
"`String::new` returns a new empty string, use `String::with_capacity` when "
"you know how much data you want to push to the string."
msgstr ""
"`String::new`는 새로운 빈 문자열을 반환합니다. `String::with_capacity`는 새"
"로 만들 문자열 버퍼에 넣을 데이터 크기를 알고 있는 경우에 사용할 수 있습니다."
#: src/std/string.md:31
msgid ""
"`String::len` returns the size of the `String` in bytes (which can be "
"different from its length in characters)."
msgstr ""
"`String::len`은 `String`의 바이트 크기를 반환합니다. (실제 문자 개수와는 다"
"를 수 있습니다.)"
#: src/std/string.md:32
msgid ""
"`String::chars` returns an iterator over the actual characters. Note that a "
"`char` can be different from what a human will consider a \"character\" due "
"to [grapheme clusters](https://docs.rs/unicode-segmentation/latest/"
"unicode_segmentation/struct.Graphemes.html)."
msgstr ""
"`String::chars`는 실제 문자(character)들에 대한 이터레이터를 반환합니다. "
"`char`로 표현되는 문자는 우리가 실제로 인식하고 사용하는 문자와는 다를 수 있"
"습니다. 자소 결합으로 문자를 표현하는 경우가 있기 때문입니다. 이에 대해서는 "
"[Grapheme Cluster](https://docs.rs/unicode-segmentation/latest/"
"unicode_segmentation/struct.Graphemes.html)를 참고하세요."
#: src/std/string.md:33
msgid ""
"When people refer to strings they could either be talking about `&str` or "
"`String`."
msgstr "사람들이 문자열이라고 말할 때에는 `&str`이거나 `String`일 수 있습니다."
#: src/std/string.md:34
msgid ""
"When a type implements `Deref<Target = T>`, the compiler will let you "
"transparently call methods from `T`."
msgstr ""
"어떤 타입이 `Deref<Target = T>`를 구현하고 있으면, 컴파일러는 여러분이 `T`의 "
"메소드들을 호출할 수 있게 도와줍니다."
#: src/std/string.md:35
msgid ""
"`String` implements `Deref<Target = str>` which transparently gives it "
"access to `str`'s methods."
msgstr ""
"`String`은 `Deref<Target = str>`을 구현하고 있기 때문에 `String`에 대해서도 "
"`str` 메소드들을 호출할 수 있습니다."
#: src/std/string.md:36
msgid "Write and compare `let s3 = s1.deref();` and `let s3 = &*s1`;."
msgstr "`let s3 = s1.deref();`와 `let s3 = &*s1;`을 비교해보세요."
#: src/std/string.md:37
msgid ""
"`String` is implemented as a wrapper around a vector of bytes, many of the "
"operations you see supported on vectors are also supported on `String`, but "
"with some extra guarantees."
msgstr ""
"`String`은 바이트 벡터의 래퍼로 구현되어 있습니다. 벡터가 지원하는 여러가지 "
"연산들을 `String`도 지원합니다. 다만 `String`은 몇가지 보장 내용이 더 있습니"
"다."
#: src/std/string.md:38
msgid "Compare the different ways to index a `String`:"
msgstr "`String`을 인덱스로 접근하는 방법들을 비교해보세요:"
#: src/std/string.md:39
msgid ""
"To a character by using `s3.chars().nth(i).unwrap()` where `i` is in-bound, "
"out-of-bounds."
msgstr ""
"`s3.chars().nth(i).unwrap()`를 이용하여 한 문자를 선택하는 경우, `i`값이 범위"
"를 벗어날 때, 벗어나지 않을 때 동작을 설명하세요."
#: src/std/string.md:40
msgid ""
"To a substring by using `s3[0..4]`, where that slice is on character "
"boundaries or not."
msgstr ""
"`s3[0..4]`를 이용해서 문자열의 일부를 선택하는데, 슬라이스가 유니코드 문자열 "
"경계에 딱 맞지 않을 경우 어떻게 되는지 설명하세요."
#: src/std/vec.md:1
msgid "`Vec`"
msgstr "`Vec`"
#: src/std/vec.md:3
msgid ""
"[`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html) is the standard "
"resizable heap-allocated buffer:"
msgstr ""
"[`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html) 는 힙에 할당된 표"
"준 가변 크기 버퍼입니다:"
#: src/std/vec.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut v1 = Vec::new();\n"
" v1.push(42);\n"
" println!(\"v1: len = {}, capacity = {}\", v1.len(), v1.capacity());\n"
"\n"
" let mut v2 = Vec::with_capacity(v1.len() + 1);\n"
" v2.extend(v1.iter());\n"
" v2.push(9999);\n"
" println!(\"v2: len = {}, capacity = {}\", v2.len(), v2.capacity());\n"
"\n"
" // Canonical macro to initialize a vector with elements.\n"
" let mut v3 = vec![0, 0, 1, 2, 3, 4];\n"
"\n"
" // Retain only the even elements.\n"
" v3.retain(|x| x % 2 == 0);\n"
" println!(\"{v3:?}\");\n"
"\n"
" // Remove consecutive duplicates.\n"
" v3.dedup();\n"
" println!(\"{v3:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut v1 = Vec::new();\n"
" v1.push(42);\n"
" println!(\"v1: len = {}, capacity = {}\", v1.len(), v1.capacity());\n"
"\n"
" let mut v2 = Vec::with_capacity(v1.len() + 1);\n"
" v2.extend(v1.iter());\n"
" v2.push(9999);\n"
" println!(\"v2: len = {}, capacity = {}\", v2.len(), v2.capacity());\n"
"\n"
" // 요소로 벡터를 초기화하는 표준 매크로입니다.\n"
" let mut v3 = vec![0, 0, 1, 2, 3, 4];\n"
"\n"
" // 짝수 요소만 유지합니다.\n"
" v3.retain(|x| x % 2 == 0);\n"
" println!(\"{v3:?}\");\n"
"\n"
" // 연속 중복을 삭제합니다.\n"
" v3.dedup();\n"
" println!(\"{v3:?}\");\n"
"}\n"
"```"
#: src/std/vec.md:29
msgid ""
"`Vec` implements [`Deref<Target = [T]>`](https://doc.rust-lang.org/std/vec/"
"struct.Vec.html#deref-methods-%5BT%5D), which means that you can call slice "
"methods on a `Vec`."
msgstr ""
"`Vec`은 [`Deref<Target = [T]>`](https://doc.rust-lang.org/std/vec/struct.Vec."
"html#deref-methods-%5BT%5D)를 구현합니다. 이는 `Vec`에서 슬라이스 메서드를 호"
"출 할 수 있다는 의미입니다."
#: src/std/vec.md:37
msgid ""
"`Vec` is a type of collection, along with `String` and `HashMap`. The data "
"it contains is stored on the heap. This means the amount of data doesn't "
"need to be known at compile time. It can grow or shrink at runtime."
msgstr ""
"`Vec`은 `String`이나 `HashMap`과 같은 컬렉션 타입입니다. 벡터는 데이터를 힙"
"에 저장합니다. 이는 컴파일 시점에 데이터 크기를 알 필요가 없다는 의미고, 런타"
"임에 더 커질 수도 작아질 수도 있습니다."
#: src/std/vec.md:40
msgid ""
"Notice how `Vec<T>` is a generic type too, but you don't have to specify `T` "
"explicitly. As always with Rust type inference, the `T` was established "
"during the first `push` call."
msgstr ""
"`Vec<T>`는 제네릭 타입이기도 합니다. 하지만 `T`를 꼭 지정해줄 필요는 없습니"
"다. 이 경우, 러스트 타입 추론이 벡터에 처음 `push`하는 데이터로 `T`를 알 수 "
"있었습니다."
#: src/std/vec.md:42
msgid ""
"`vec![...]` is a canonical macro to use instead of `Vec::new()` and it "
"supports adding initial elements to the vector."
msgstr ""
"`vec![...]`는 `Vec::new()` 대신 쓸 수 있는 표준 매크로로서, 초기 데이터를 추"
"가한 벡터를 생성할 수 있습니다."
#: src/std/vec.md:44
msgid ""
"To index the vector you use `[` `]`, but they will panic if out of bounds. "
"Alternatively, using `get` will return an `Option`. The `pop` function will "
"remove the last element."
msgstr ""
"벡터는 `[` `]`를 사용하여 인덱스로 접근할 수 있습니다. 하지만 범위를 벗어나"
"면 패닉이 발생합니다. 대신 `get`을 사용하면 `Option`을 반환합니다. `pop` 함수"
"는 마지막 요소를 제거합니다."
#: src/std/vec.md:46
msgid ""
"Show iterating over a vector and mutating the value: `for e in &mut v { *e "
"+= 50; }`"
msgstr ""
"벡터를 순회하면서 값을 변경할 수도 있음을 보여주세요: `for e in &mut v { *e "
"+= 50; }`"
#: src/std/hashmap.md:1 src/bare-metal/no_std.md:46
msgid "`HashMap`"
msgstr "`HashMap`"
#: src/std/hashmap.md:3
msgid "Standard hash map with protection against HashDoS attacks:"
msgstr "HashDoS 공격으로부터 보호되는 표준 해시 맵입니다:"
#: src/std/hashmap.md:5
msgid ""
"```rust,editable\n"
"use std::collections::HashMap;\n"
"\n"
"fn main() {\n"
" let mut page_counts = HashMap::new();\n"
" page_counts.insert(\"Adventures of Huckleberry Finn\".to_string(), "
"207);\n"
" page_counts.insert(\"Grimms' Fairy Tales\".to_string(), 751);\n"
" page_counts.insert(\"Pride and Prejudice\".to_string(), 303);\n"
"\n"
" if !page_counts.contains_key(\"Les Misérables\") {\n"
" println!(\"We know about {} books, but not Les Misérables.\",\n"
" page_counts.len());\n"
" }\n"
"\n"
" for book in [\"Pride and Prejudice\", \"Alice's Adventure in "
"Wonderland\"] {\n"
" match page_counts.get(book) {\n"
" Some(count) => println!(\"{book}: {count} pages\"),\n"
" None => println!(\"{book} is unknown.\")\n"
" }\n"
" }\n"
"\n"
" // Use the .entry() method to insert a value if nothing is found.\n"
" for book in [\"Pride and Prejudice\", \"Alice's Adventure in "
"Wonderland\"] {\n"
" let page_count: &mut i32 = page_counts.entry(book.to_string())."
"or_insert(0);\n"
" *page_count += 1;\n"
" }\n"
"\n"
" println!(\"{page_counts:#?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::collections::HashMap;\n"
"\n"
"fn main() {\n"
" let mut page_counts = HashMap::new();\n"
" page_counts.insert(\"Adventures of Huckleberry Finn\".to_string(), "
"207);\n"
" page_counts.insert(\"Grimms' Fairy Tales\".to_string(), 751);\n"
" page_counts.insert(\"Pride and Prejudice\".to_string(), 303);\n"
"\n"
" if !page_counts.contains_key(\"Les Misérables\") {\n"
" println!(\"We know about {} books, but not Les Misérables.\",\n"
" page_counts.len());\n"
" }\n"
"\n"
" for book in [\"Pride and Prejudice\", \"Alice's Adventure in "
"Wonderland\"] {\n"
" match page_counts.get(book) {\n"
" Some(count) => println!(\"{book}: {count} pages\"),\n"
" None => println!(\"{book} is unknown.\")\n"
" }\n"
" }\n"
"\n"
" // 아무것도 찾을 수 없는 경우 .entry() 메서드를 사용하여 값을 삽입합니"
"다.\n"
" for book in [\"Pride and Prejudice\", \"Alice's Adventure in "
"Wonderland\"] {\n"
" let page_count: &mut i32 = page_counts.entry(book.to_string())."
"or_insert(0);\n"
" *page_count += 1;\n"
" }\n"
"\n"
" println!(\"{page_counts:#?}\");\n"
"}\n"
"```"
#: src/std/hashmap.md:38
msgid ""
"`HashMap` is not defined in the prelude and needs to be brought into scope."
msgstr ""
"`HashMap`은 prelude에 정의되어 있지 않기 때문에 명시적으로 추가해줘야 합니다."
#: src/std/hashmap.md:39
msgid ""
"Try the following lines of code. The first line will see if a book is in the "
"hashmap and if not return an alternative value. The second line will insert "
"the alternative value in the hashmap if the book is not found."
msgstr ""
"아래 코드를 테스트해보세요. 첫 문장에서는 해시맵에 책이 있는지 검사하여, 없으"
"면 디폴트 값을 반환합니다. 두번 째 문장에서는 해시맵에 해당 책이 없는 경우, "
"지정한 값을 해시맵에 추가한 뒤 그 값을 반환합니다."
#: src/std/hashmap.md:41
msgid ""
"```rust,ignore\n"
" let pc1 = page_counts\n"
" .get(\"Harry Potter and the Sorcerer's Stone \")\n"
" .unwrap_or(&336);\n"
" let pc2 = page_counts\n"
" .entry(\"The Hunger Games\".to_string())\n"
" .or_insert(374);\n"
"```"
msgstr ""
"```rust,ignore\n"
" let pc1 = page_counts\n"
" .get(\"Harry Potter and the Sorcerer's Stone \")\n"
" .unwrap_or(&336);\n"
" let pc2 = page_counts\n"
" .entry(\"The Hunger Games\".to_string())\n"
" .or_insert(374);\n"
"```"
#: src/std/hashmap.md:49
msgid "Unlike `vec!`, there is unfortunately no standard `hashmap!` macro."
msgstr "안타깝지만 `hashmap!`같은 매크로가 없습니다."
#: src/std/hashmap.md:50
msgid ""
"Although, since Rust 1.56, HashMap implements [`From<[(K, V); N]>`](https://"
"doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#impl-"
"From%3C%5B(K,+V);+N%5D%3E-for-HashMap%3CK,+V,+RandomState%3E), which allows "
"us to easily initialize a hash map from a literal array:"
msgstr ""
"러스트 1.56부터는 `HashMap`이 [`From<[(K, V); N]>`](https://doc.rust-lang."
"org/std/collections/hash_map/struct.HashMap.html#impl-From%3C%5B(K,+V);"
"+N%5D%3E-for-HashMap%3CK,+V,+RandomState%3E)을 구현하기 때문에 배열 리터럴을 "
"이용하여 쉽게 해시맵을 초기화할 수 있습니다:"
#: src/std/hashmap.md:52
msgid ""
"```rust,ignore\n"
" let page_counts = HashMap::from([\n"
" (\"Harry Potter and the Sorcerer's Stone\".to_string(), 336),\n"
" (\"The Hunger Games\".to_string(), 374),\n"
" ]);\n"
"```"
msgstr ""
"```rust,ignore\n"
" let page_counts = HashMap::from([\n"
" (\"Harry Potter and the Sorcerer's Stone\".to_string(), 336),\n"
" (\"The Hunger Games\".to_string(), 374),\n"
" ]);\n"
"```"
#: src/std/hashmap.md:59
msgid ""
"Alternatively HashMap can be built from any `Iterator` which yields key-"
"value tuples."
msgstr "키-값 쌍에 대한 `Iterator`로 해시맵을 만들 수도 있습니다."
#: src/std/hashmap.md:60
msgid ""
"We are showing `HashMap<String, i32>`, and avoid using `&str` as key to make "
"examples easier. Using references in collections can, of course, be done, "
"but it can lead into complications with the borrow checker."
msgstr ""
"예제 코드에서는 편의상 해시맵의 키로 `&str`를 사용하지 않았습니다. 물론 컬렉"
"션에 참조를 사용할 수도 있습니다. 다만 참조를 사용하게 되면 빌림 검사기 때문"
"에 복잡해 질 수 있습니다."
#: src/std/hashmap.md:62
msgid ""
"Try removing `to_string()` from the example above and see if it still "
"compiles. Where do you think we might run into issues?"
msgstr ""
"예제 코드에서 `to_string()`을 없애도 컴파일에 문제가 없는지 확인해보세요. 어"
"떤 문제에 부딪힐까요?"
#: src/std/hashmap.md:64
msgid ""
"This type has several \"method-specific\" return types, such as `std::"
"collections::hash_map::Keys`. These types often appear in searches of the "
"Rust docs. Show students the docs for this type, and the helpful link back "
"to the `keys` method."
msgstr ""
"해시맵의 몇 몇 메서드는 해시맵 내부의 특별한 타입(예를 들어 `std::"
"collections::hash_map::Keys`)들을 리턴합니다. 이러한 타입들은 Rust 문서에서"
"도 검색할 수 있습니다. 수강생들에게 이 타입들에 대한 문서를 보여주고, 이 문서"
"에 `keys` 메서드로의 역 링크가 있음을 알려주세요."
#: src/std/box.md:1
msgid "`Box`"
msgstr "`Box`"
#: src/std/box.md:3
msgid ""
"[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html) is an owned "
"pointer to data on the heap:"
msgstr ""
"[`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)는 힙 데이터에 대"
"한 소유 포인터입니다:"
#: src/std/box.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let five = Box::new(5);\n"
" println!(\"five: {}\", *five);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let five = Box::new(5);\n"
" println!(\"five: {}\", *five);\n"
"}\n"
"```"
#: src/std/box.md:13
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - -. .- - - - - - -.\n"
": : : :\n"
": five : : :\n"
": +-----+ : : +-----+ :\n"
": | o---|---+-----+-->| 5 | :\n"
": +-----+ : : +-----+ :\n"
": : : :\n"
": : : :\n"
"`- - - - - - -' `- - - - - - -'\n"
"```"
msgstr ""
"```bob\n"
" 스택 힙\n"
".- - - - - - -. .- - - - - - -.\n"
": : : :\n"
": five : : :\n"
": +-----+ : : +-----+ :\n"
": | o---|---+-----+-->| 5 | :\n"
": +-----+ : : +-----+ :\n"
": : : :\n"
": : : :\n"
"`- - - - - - -' `- - - - - - -'\n"
"```"
#: src/std/box.md:26
msgid ""
"`Box<T>` implements `Deref<Target = T>`, which means that you can [call "
"methods from `T` directly on a `Box<T>`](https://doc.rust-lang.org/std/ops/"
"trait.Deref.html#more-on-deref-coercion)."
msgstr ""
"`Box<T>`은 [`Deref<Target = T>`](https://doc.rust-lang.org/std/ops/trait."
"Deref.html#more-on-deref-coercion)를 구현합니다. 이는 [`Box<T>`에서 `T` 메서"
"드를 직접 호출](https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-"
"deref-coercion) 할 수 있다는 의미입니다."
#: src/std/box.md:34
msgid ""
"`Box` is like `std::unique_ptr` in C++, except that it's guaranteed to be "
"not null. "
msgstr ""
"`Box`는 C++의 `std::unique_ptr`과 비슷합니다. 차이라면 `Box`는 널이 아님을 보"
"장한다는 점입니다. "
#: src/std/box.md:35
msgid ""
"In the above example, you can even leave out the `*` in the `println!` "
"statement thanks to `Deref`. "
msgstr ""
"`Deref` 덕분에 위 예제의 `println!`문에 사용된 `*`를 빼도 문제가 없습니다. "
#: src/std/box.md:36
msgid "A `Box` can be useful when you:"
msgstr "`Box`는 아래의 경우에 유용합니다:"
#: src/std/box.md:37
msgid ""
"have a type whose size that can't be known at compile time, but the Rust "
"compiler wants to know an exact size."
msgstr "타입 크기를 컴파일 시점에 알 수 없는 경우."
#: src/std/box.md:38
msgid ""
"want to transfer ownership of a large amount of data. To avoid copying large "
"amounts of data on the stack, instead store the data on the heap in a `Box` "
"so only the pointer is moved."
msgstr ""
"아주 큰 데이터의 소유권을 전달하고 싶은 경우. 스택에 있는 큰 데이터를 복사하"
"는 대신 `Box`를 이용하여 데이터는 힙에 저장하고 포인터만 이동하면 됩니다."
#: src/std/box-recursive.md:1
msgid "Box with Recursive Data Structures"
msgstr "재귀자료 구조에서의 `Box`"
#: src/std/box-recursive.md:3
msgid ""
"Recursive data types or data types with dynamic sizes need to use a `Box`:"
msgstr "재귀 데이터나 동적크기의 데이터 타입은 `Box`타입을 사용해야 합니다:"
#: src/std/box-recursive.md:5 src/std/box-niche.md:3
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"enum List<T> {\n"
" Cons(T, Box<List<T>>),\n"
" Nil,\n"
"}\n"
"\n"
"fn main() {\n"
" let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::"
"new(List::Nil))));\n"
" println!(\"{list:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"enum List<T> {\n"
" Cons(T, Box<List<T>>),\n"
" Nil,\n"
"}\n"
"\n"
"fn main() {\n"
" let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::"
"new(List::Nil))));\n"
" println!(\"{list:?}\");\n"
"}\n"
"```"
#: src/std/box-recursive.md:18
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - - "
"- -.\n"
": : : :\n"
": "
"list : : :\n"
": +------+----+----+ : : +------+----+----+ +------+----+----"
"+ :\n"
": | Cons | 1 | o--+----+-----+--->| Cons | 2 | o--+--->| Nil | // | // "
"| :\n"
": +------+----+----+ : : +------+----+----+ +------+----+----"
"+ :\n"
": : : :\n"
": : : :\n"
"'- - - - - - - - - - - - -' '- - - - - - - - - - - - - - - - - - - - - - "
"- -'\n"
"```"
msgstr ""
"```bob\n"
" 스택 힙\n"
".- - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - - "
"- -.\n"
": : : :\n"
": "
"list : : :\n"
": +------+----+----+ : : +------+----+----+ +------+----+----"
"+ :\n"
": | Cons | 1 | o--+----+-----+--->| Cons | 2 | o--+--->| Nil | // | // "
"| :\n"
": +------+----+----+ : : +------+----+----+ +------+----+----"
"+ :\n"
": : : :\n"
": : : :\n"
"'- - - - - - - - - - - - -' '- - - - - - - - - - - - - - - - - - - - - - "
"- -'\n"
"```"
#: src/std/box-recursive.md:33
msgid ""
"If `Box` was not used and we attempted to embed a `List` directly into the "
"`List`, the compiler would not compute a fixed size of the struct in memory "
"(`List` would be of infinite size)."
msgstr ""
"만일 `Box`를 사용하지 않고 `List`에 직접 `List`를 포함하려고 시도한다면, 컴파"
"일러는 구조체의 고정 크기를 계산할 수 없습니다. 컴파일러가 보기에 무한대의 크"
"기로 보일 것입니다."
#: src/std/box-recursive.md:36
msgid ""
"`Box` solves this problem as it has the same size as a regular pointer and "
"just points at the next element of the `List` in the heap."
msgstr ""
"`Box`는 일반 포인터와 크기가 같기 때문에 크기를 계산하는 데 문제가 없습니다. "
"다만 힙에 위치한 `List`의 다음 요소를 가리킬 뿐입니다."
#: src/std/box-recursive.md:39
msgid ""
"Remove the `Box` in the List definition and show the compiler error. "
"\"Recursive with indirection\" is a hint you might want to use a Box or "
"reference of some kind, instead of storing a value directly."
msgstr ""
"`List` 정의에서 `Box`를 제거하면 어떤 컴파일러 에러가 나오는지 같이 살펴보세"
"요. “Recursive with indirection”라는 메시지를 보면, 값을 직접 저장하는 대신 "
"`Box`나 비슷한 다른 종류의 참조 타입이 필요하다는 힌트를 얻을 수 있습니다."
#: src/std/box-niche.md:16
msgid ""
"A `Box` cannot be empty, so the pointer is always valid and non-`null`. This "
"allows the compiler to optimize the memory layout:"
msgstr ""
"`Box`는 비어있을 수 없습니다. 따라서 포인터는 항상 유효하며 `null`이 아닙니"
"다. 이는 컴파일러가 메모리 레이아웃을 최적화 할 수 있게 해줍니다:"
#: src/std/box-niche.md:19
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - - "
"-.\n"
": : : :\n"
": "
"list : : :\n"
": +----+----+ : : +----+----+ +----+------"
"+ :\n"
": | 1 | o--+-----------+-----+--->| 2 | o--+--->| // | null "
"| :\n"
": +----+----+ : : +----+----+ +----+------"
"+ :\n"
": : : :\n"
": : : :\n"
"`- - - - - - - - - - - - -' '- - - - - - - - - - - - - - - - - - - - - - "
"-'\n"
"```"
msgstr ""
"```bob\n"
" 스택 힙\n"
".- - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - - "
"-.\n"
": : : :\n"
": "
"list : : :\n"
": +----+----+ : : +----+----+ +----+------"
"+ :\n"
": | 1 | o--+-----------+-----+--->| 2 | o--+--->| // | null "
"| :\n"
": +----+----+ : : +----+----+ +----+------"
"+ :\n"
": : : :\n"
": : : :\n"
"`- - - - - - - - - - - - -' '- - - - - - - - - - - - - - - - - - - - - - "
"-'\n"
"```"
#: src/std/rc.md:1
msgid "`Rc`"
msgstr "`Rc`"
#: src/std/rc.md:3
msgid ""
"[`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html) is a reference-"
"counted shared pointer. Use this when you need to refer to the same data "
"from multiple places:"
msgstr ""
"[`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html)는 참조 카운팅 공유 포"
"인터입니다. 여러 위치에서 동일한 데이터를 참조해야할 경우 사용합니다:"
#: src/std/rc.md:6
msgid ""
"```rust,editable\n"
"use std::rc::Rc;\n"
"\n"
"fn main() {\n"
" let mut a = Rc::new(10);\n"
" let mut b = Rc::clone(&a);\n"
"\n"
" println!(\"a: {a}\");\n"
" println!(\"b: {b}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::rc::Rc;\n"
"\n"
"fn main() {\n"
" let mut a = Rc::new(10);\n"
" let mut b = Rc::clone(&a);\n"
"\n"
" println!(\"a: {a}\");\n"
" println!(\"b: {b}\");\n"
"}\n"
"```"
#: src/std/rc.md:18
msgid ""
"See [`Arc`](../concurrency/shared_state/arc.md) and [`Mutex`](https://doc."
"rust-lang.org/std/sync/struct.Mutex.html) if you are in a multi-threaded "
"context."
msgstr ""
"멀티스레드 환경에서 작업하는 경우 [`Arc`](../concurrency/shared_state/arc.md)"
"와 [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)를 참조하세"
"요."
#: src/std/rc.md:19
msgid ""
"You can _downgrade_ a shared pointer into a [`Weak`](https://doc.rust-lang."
"org/std/rc/struct.Weak.html) pointer to create cycles that will get dropped."
msgstr ""
"drop 가능한 순환 구조를 만들기 위해 공유 포인터를 [`Weak`](https://doc.rust-"
"lang.org/std/rc/struct.Weak.html) 포인터로 _다운그레이드_할 수도 있습니다."
#: src/std/rc.md:29
msgid ""
"`Rc`'s count ensures that its contained value is valid for as long as there "
"are references."
msgstr ""
"`Rc`는 참조 카운트를 통해 참조가 있는 동안은 `Rc`가 가리키고 있는 값이 메모리"
"에서 해제되지 않음을 보장합니다."
#: src/std/rc.md:30
msgid "`Rc` in Rust is like `std::shared_ptr` in C++."
msgstr "C++의 `std::shared_ptr`와 유사합니다."
#: src/std/rc.md:31
msgid ""
"`Rc::clone` is cheap: it creates a pointer to the same allocation and "
"increases the reference count. Does not make a deep clone and can generally "
"be ignored when looking for performance issues in code."
msgstr ""
"`clone`은 비용이 거의 들지 않습니다. 같은 곳을 가리키는 포인터를 하나 더 만들"
"고, 참조 카운트를 늘립니다. 포인터가 가리키는 값 자체가 복제(깊은 복제)되지"
"는 않으며, 그래서 코드에서 성능 문제가 있는지 검토할 때 일반적으로 `Rc`를 "
"`clone`하는 것은 무시할 수 있습니다."
#: src/std/rc.md:32
msgid ""
"`make_mut` actually clones the inner value if necessary (\"clone-on-write\") "
"and returns a mutable reference."
msgstr ""
"`make_mut`는 실제로 필요한 경우에 내부 값을 복제하고(\"clone-on-write\") 가"
"변 참조를 반환합니다."
#: src/std/rc.md:33
msgid "Use `Rc::strong_count` to check the reference count."
msgstr "참조 카운트를 확인하려면 `Rc::strong_count`를 사용하세요."
#: src/std/rc.md:34
msgid ""
"`Rc::downgrade` gives you a _weakly reference-counted_ object to create "
"cycles that will be dropped properly (likely in combination with `RefCell`, "
"on the next slide)."
msgstr ""
"`Rc`는 `downgrade()`로 다운그레이드하여 _약하게 참조 카운트되는(weekly "
"reference-counted)_ 객체가 될 있습니다. 그러면 순환구조라 하더라도 drop이 가"
"능합니다. (아마도 `RefCell` 을 함께 사용해야 할 것입니다.)"
#: src/std/cell.md:1
msgid "`Cell` and `RefCell`"
msgstr "`Cell`과 `RefCell`"
#: src/std/cell.md:3
msgid ""
"\\[`Cell`\\]\\[https://doc.rust-lang.org/std/cell/struct.Cell.html\\] and "
"[`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html) "
"implement what Rust calls _interior mutability:_ mutation of values in an "
"immutable context."
msgstr ""
"[`Cell`](https://doc.rust-lang.org/std/cell/struct.Cell.html 과 [`RefCell`]"
"(https://doc.rust-lang.org/std/cell/struct.RefCell.html)은 러스트에서 _내적 "
"가변성(interior mutability)_이라고 부르는 것을 구현합니다. 이를 이용하면 불변"
"인 객체의 값을 수정할 수 있습니다."
#: src/std/cell.md:8
msgid ""
"`Cell` is typically used for simple types, as it requires copying or moving "
"values. More complex interior types typically use `RefCell`, which tracks "
"shared and exclusive references at runtime and panics if they are misused."
msgstr ""
"`Cell`은 간단한 타입에 대해서 주로 사용됩니다. 왜냐하면 `Cell`에 있는 값을 읽"
"거나 쓸때에는 복사 혹은 이동을 해야만 하기 때문입니다. 복잡한 타입이라면 "
"`RefCell`이 더 보편적입니다. 이를 이용하면 참조를 통해 값을 읽거나 쓰게 해 주"
"는 대신, 그 참조들이 올바른지를 런타임에 체크하고, 제대로 사용되지 않을 경우 "
"패닉을 발생시킵니다."
#: src/std/cell.md:12
msgid ""
"```rust,editable\n"
"use std::cell::RefCell;\n"
"use std::rc::Rc;\n"
"\n"
"#[derive(Debug, Default)]\n"
"struct Node {\n"
" value: i64,\n"
" children: Vec<Rc<RefCell<Node>>>,\n"
"}\n"
"\n"
"impl Node {\n"
" fn new(value: i64) -> Rc<RefCell<Node>> {\n"
" Rc::new(RefCell::new(Node { value, ..Node::default() }))\n"
" }\n"
"\n"
" fn sum(&self) -> i64 {\n"
" self.value + self.children.iter().map(|c| c.borrow().sum()).sum::"
"<i64>()\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let root = Node::new(1);\n"
" root.borrow_mut().children.push(Node::new(5));\n"
" let subtree = Node::new(10);\n"
" subtree.borrow_mut().children.push(Node::new(11));\n"
" subtree.borrow_mut().children.push(Node::new(12));\n"
" root.borrow_mut().children.push(subtree);\n"
"\n"
" println!(\"graph: {root:#?}\");\n"
" println!(\"graph sum: {}\", root.borrow().sum());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::cell::RefCell;\n"
"use std::rc::Rc;\n"
"\n"
"#[derive(Debug, Default)]\n"
"struct Node {\n"
" value: i64,\n"
" children: Vec<Rc<RefCell<Node>>>,\n"
"}\n"
"\n"
"impl Node {\n"
" fn new(value: i64) -> Rc<RefCell<Node>> {\n"
" Rc::new(RefCell::new(Node { value, ..Node::default() }))\n"
" }\n"
"\n"
" fn sum(&self) -> i64 {\n"
" self.value + self.children.iter().map(|c| c.borrow().sum()).sum::"
"<i64>()\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let root = Node::new(1);\n"
" root.borrow_mut().children.push(Node::new(5));\n"
" let subtree = Node::new(10);\n"
" subtree.borrow_mut().children.push(Node::new(11));\n"
" subtree.borrow_mut().children.push(Node::new(12));\n"
" root.borrow_mut().children.push(subtree);\n"
"\n"
" println!(\"graph: {root:#?}\");\n"
" println!(\"graph sum: {}\", root.borrow().sum());\n"
"}\n"
"```"
#: src/std/cell.md:47
msgid ""
"If we were using `Cell` instead of `RefCell` in this example, we would have "
"to move the `Node` out of the `Rc` to push children, then move it back in. "
"This is safe because there's always one, un-referenced value in the cell, "
"but it's not ergonomic."
msgstr ""
"이 예제에서 `RefCell`대신 `Cell`을 썼었다면, `Node`에 자식 노느를 추가하기 위"
"해서, `Node`를 `Rc`밖으로 이동시킨 다음, 자식 노드를 추가하고, 다시 `Rc`안으"
"로 이동시켜야 했을 겁니다. 이렇게 해야만 하는 이유는 안전 때문입니다. Cell 내"
"부의 그 값이 오직 하나 존재하며, 그 값에 대한 참조가 없다는 것이 보장되기 때"
"문입니다. 물론 편리하지는 않습니다."
#: src/std/cell.md:48
msgid ""
"To do anything with a Node, you must call a `RefCell` method, usually "
"`borrow` or `borrow_mut`."
msgstr ""
"노드를 이동하거나 복사하지 않고 그대로 사용하기 위해서는 `RefCell`로 감싼다"
"음 `borrow`나 `borrow_mut`메서드를 이용해야 합니다."
#: src/std/cell.md:49
msgid ""
"Demonstrate that reference loops can be created by adding `root` to `subtree."
"children` (don't try to print it!)."
msgstr ""
"`root`를 `subtree.children`에 추가해서 순환 참조가 생길 수 있음을 보여주세요 "
"(그래프를 출력하지는 마세요!)."
#: src/std/cell.md:50
msgid ""
"To demonstrate a runtime panic, add a `fn inc(&mut self)` that increments "
"`self.value` and calls the same method on its children. This will panic in "
"the presence of the reference loop, with `thread 'main' panicked at 'already "
"borrowed: BorrowMutError'`."
msgstr ""
"`self.value`를 증가시키는 메서드인`fn inc(&mut self)`를 추가하고 그 메서드를 "
"자식노드에서 호출하세요. 그러면 `thread 'main' panicked at 'already "
"borrowed: BorrowMutError'` 런타임 패닉이 발생함을 보이세요."
#: src/modules.md:3
msgid "We have seen how `impl` blocks let us namespace functions to a type."
msgstr "`impl`블록은 해당 타입의 함수들에 대한 네임스페이스를 제공합니다."
#: src/modules.md:5
msgid "Similarly, `mod` lets us namespace types and functions:"
msgstr "마찬가지로, `mod`는 타입과 함수들에 대해 네임스페이스를 제공합니다:"
#: src/modules.md:7
msgid ""
"```rust,editable\n"
"mod foo {\n"
" pub fn do_something() {\n"
" println!(\"In the foo module\");\n"
" }\n"
"}\n"
"\n"
"mod bar {\n"
" pub fn do_something() {\n"
" println!(\"In the bar module\");\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" foo::do_something();\n"
" bar::do_something();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"mod foo {\n"
" pub fn do_something() {\n"
" println!(\"In the foo module\");\n"
" }\n"
"}\n"
"\n"
"mod bar {\n"
" pub fn do_something() {\n"
" println!(\"In the bar module\");\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" foo::do_something();\n"
" bar::do_something();\n"
"}\n"
"```"
#: src/modules.md:28
msgid ""
"Packages provide functionality and include a `Cargo.toml` file that "
"describes how to build a bundle of 1+ crates."
msgstr ""
"패키지는 기능을 제공하며 하나의 대표 `Cargo.toml` 파일을 포함합니다. 패키지"
"를 구성하는 크레이트들을 빌드하는 방법이 이 파일에 기술됩니다."
#: src/modules.md:29
msgid ""
"Crates are a tree of modules, where a binary crate creates an executable and "
"a library crate compiles to a library."
msgstr ""
"크레이트는 모듈의 트리입니다. 바이너리 크레이트는 실행파일로 빌드되고, 라이브"
"러리 크레이트는 라이브러리로 빌드됩니다."
#: src/modules.md:30
msgid "Modules define organization, scope, and are the focus of this section."
msgstr "모듈은 코드를 조직화하고 스코프를 정의하는 단위입니다."
#: src/modules/visibility.md:3
msgid "Modules are a privacy boundary:"
msgstr "모듈의 타입이나 함수는 기본적으로 바깥에 노출되지 않습니다:"
#: src/modules/visibility.md:5
msgid "Module items are private by default (hides implementation details)."
msgstr "따라서 모듈의 세부 구현 내용이 감춰집니다."
#: src/modules/visibility.md:6
msgid "Parent and sibling items are always visible."
msgstr "부모와 이웃 항목은 언제나 접근 가능합니다."
#: src/modules/visibility.md:7
msgid ""
"In other words, if an item is visible in module `foo`, it's visible in all "
"the descendants of `foo`."
msgstr ""
"즉, 모듈 `foo`에서 접근 가능한 항목이라면 `foo` 아래의 모든 모듈에서 접근가능"
"합니다."
#: src/modules/visibility.md:10
msgid ""
"```rust,editable\n"
"mod outer {\n"
" fn private() {\n"
" println!(\"outer::private\");\n"
" }\n"
"\n"
" pub fn public() {\n"
" println!(\"outer::public\");\n"
" }\n"
"\n"
" mod inner {\n"
" fn private() {\n"
" println!(\"outer::inner::private\");\n"
" }\n"
"\n"
" pub fn public() {\n"
" println!(\"outer::inner::public\");\n"
" super::private();\n"
" }\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" outer::public();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"mod outer {\n"
" fn private() {\n"
" println!(\"outer::private\");\n"
" }\n"
"\n"
" pub fn public() {\n"
" println!(\"outer::public\");\n"
" }\n"
"\n"
" mod inner {\n"
" fn private() {\n"
" println!(\"outer::inner::private\");\n"
" }\n"
"\n"
" pub fn public() {\n"
" println!(\"outer::inner::public\");\n"
" super::private();\n"
" }\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" outer::public();\n"
"}\n"
"```"
#: src/modules/visibility.md:39
msgid "Use the `pub` keyword to make modules public."
msgstr "`pub` 키워드는 모듈에도 사용할 수 있습니다."
#: src/modules/visibility.md:41
msgid ""
"Additionally, there are advanced `pub(...)` specifiers to restrict the scope "
"of public visibility."
msgstr ""
"또한, 고급 기능으로 `pub(...)` 지정자를 사용하여 공개 범위를 제한할 수 있습니"
"다."
#: src/modules/visibility.md:43
msgid ""
"See the [Rust Reference](https://doc.rust-lang.org/reference/visibility-and-"
"privacy.html#pubin-path-pubcrate-pubsuper-and-pubself)."
msgstr ""
"[공식 문서](https://doc.rust-lang.org/reference/visibility-and-privacy."
"html#pubin-path-pubcrate-pubsuper-and-pubself)를 참고하세요."
#: src/modules/visibility.md:44
msgid "Configuring `pub(crate)` visibility is a common pattern."
msgstr "`pub(crate)`로 가시성을 지정하는 것이 자주 쓰입니다."
#: src/modules/visibility.md:45
msgid "Less commonly, you can give visibility to a specific path."
msgstr "자주 쓰이진 않지만 특정 경로에 대해서만 가시성을 부여할 수 있습니다."
#: src/modules/visibility.md:46
msgid ""
"In any case, visibility must be granted to an ancestor module (and all of "
"its descendants)."
msgstr ""
"어떤 경우이든 가시성이 부여되면 해당 모듈을 포함하여 하위의 모든 모듈이 적용"
"받습니다."
#: src/modules/paths.md:3
msgid "Paths are resolved as follows:"
msgstr "경로는 아래와 같이 구분합니다:"
#: src/modules/paths.md:5
msgid "As a relative path:"
msgstr "상대 경로:"
#: src/modules/paths.md:6
msgid "`foo` or `self::foo` refers to `foo` in the current module,"
msgstr "`foo` 또는 `self::foo`는 현재 모듈 내부의 `foo`를 가리킵니다,"
#: src/modules/paths.md:7
msgid "`super::foo` refers to `foo` in the parent module."
msgstr "`super::foo`는 부모 모듈의 `foo`를 가리킵니다."
#: src/modules/paths.md:9
msgid "As an absolute path:"
msgstr "절대 경로:"
#: src/modules/paths.md:10
msgid "`crate::foo` refers to `foo` in the root of the current crate,"
msgstr "`crate::foo`는 현재 크레이트 루트의 `foo`를 가리킵니다,"
#: src/modules/paths.md:11
msgid "`bar::foo` refers to `foo` in the `bar` crate."
msgstr "`bar::foo`는 `bar`크레이트의 `foo`를 가리킵니다."
#: src/modules/paths.md:13
msgid ""
"A module can bring symbols from another module into scope with `use`. You "
"will typically see something like this at the top of each module:"
msgstr ""
"모듈은 `use`를 사용하여 다른 모듈의 심볼을 내 스코프로 가져올 수 있습니다. 일"
"반적으로 각 모듈의 상단에 다음과 같은 내용이 옵니다:"
#: src/modules/paths.md:16
msgid ""
"```rust,editable\n"
"use std::collections::HashSet;\n"
"use std::mem::transmute;\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::collections::HashSet;\n"
"use std::mem::transmute;\n"
"```"
#: src/modules/filesystem.md:3
msgid ""
"Omitting the module content will tell Rust to look for it in another file:"
msgstr ""
"모듈의 내용을 기술하지 않으면, 러스트는 다른 파일에서 그 내용을 읽습니다:"
#: src/modules/filesystem.md:5
msgid ""
"```rust,editable,compile_fail\n"
"mod garden;\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"mod garden;\n"
"```"
#: src/modules/filesystem.md:9
msgid ""
"This tells rust that the `garden` module content is found at `src/garden."
"rs`. Similarly, a `garden::vegetables` module can be found at `src/garden/"
"vegetables.rs`."
msgstr ""
"위 코드는 러스트로 하여금 `garden`모듈의 내용을 `src/garden.rs`에서 찾도록 합"
"니다. 비슷하게, `garden::vegetables` 모듈은 `src/garden/vegetables.rs`에서 찾"
"습니다."
#: src/modules/filesystem.md:12
msgid "The `crate` root is in:"
msgstr "`crate(크레이트)`의 루트는 아래 경로 입니다:"
#: src/modules/filesystem.md:14
msgid "`src/lib.rs` (for a library crate)"
msgstr "`src/lib.rs` (라이브러리 크레이트)"
#: src/modules/filesystem.md:15
msgid "`src/main.rs` (for a binary crate)"
msgstr "`src/main.rs` (바이너리 크레이트)"
#: src/modules/filesystem.md:17
msgid ""
"Modules defined in files can be documented, too, using \"inner doc "
"comments\". These document the item that contains them -- in this case, a "
"module."
msgstr ""
"모듈도 \"내부 문서 주석\"을 사용하여 문서화할 수 있습니다. 이러한 모듈은 모듈"
"이 포함된 항목(이 경우에는 모듈)을 문서화합니다."
#: src/modules/filesystem.md:20
msgid ""
"```rust,editable,compile_fail\n"
"//! This module implements the garden, including a highly performant "
"germination\n"
"//! implementation.\n"
"\n"
"// Re-export types from this module.\n"
"pub use seeds::SeedPacket;\n"
"pub use garden::Garden;\n"
"\n"
"/// Sow the given seed packets.\n"
"pub fn sow(seeds: Vec<SeedPacket>) { todo!() }\n"
"\n"
"/// Harvest the produce in the garden that is ready.\n"
"pub fn harvest(garden: &mut Garden) { todo!() }\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"//! 이 모듈은 높은 성능의 발아 구현을 비롯하여 정원을\n"
"//! 구현합니다.\n"
"\n"
"// 이 모듈에 정의된 타입을 밖으로 공개합니다.\n"
"pub use seeds::SeedPacket;\n"
"pub use garden::Garden;\n"
"\n"
"/// 지정된 씨앗 패킷을 뿌립니다.\n"
"pub fn sow(seeds: Vec<SeedPacket>) { todo!() }\n"
"\n"
"/// 정원에서 준비된 농산물을 수확합니다.\n"
"pub fn harvest(garden: &mut Garden) { todo!() }\n"
"```"
#: src/modules/filesystem.md:37
msgid ""
"Before Rust 2018, modules needed to be located at `module/mod.rs` instead of "
"`module.rs`, and this is still a working alternative for editions after 2018."
msgstr ""
"`module/mod.rs`를 `module.rs`로 바꾼다 하더라도 Rust 2018에서는 하위 모듈을 "
"사용할 수 있습니다."
#: src/modules/filesystem.md:39
msgid ""
"The main reason to introduce `filename.rs` as alternative to `filename/mod."
"rs` was because many files named `mod.rs` can be hard to distinguish in IDEs."
msgstr ""
"`filename.rs`를 `filename/mod.rs`대신 사용할 수 있도록 하는 주된 이유는, "
"`mod.rs`라는 이름을 가진 파일이 많을 경우 IDE에서 이들을 서로 구별하는게 힘들"
"기 때문입니다."
#: src/modules/filesystem.md:42
msgid "Deeper nesting can use folders, even if the main module is a file:"
msgstr ""
"폴더를 이용해서 더 깊은 계층 구조를 구현할 수 있습니다. 심지어는 메인 모듈이 "
"파일이더라도요:"
#: src/modules/filesystem.md:44
msgid ""
"```ignore\n"
"src/\n"
"├── main.rs\n"
"├── top_module.rs\n"
"└── top_module/\n"
" └── sub_module.rs\n"
"```"
msgstr ""
"```ignore\n"
"src/\n"
"├── main.rs\n"
"├── top_module.rs\n"
"└── top_module/\n"
" └── sub_module.rs\n"
"```"
#: src/modules/filesystem.md:52
msgid ""
"The place rust will look for modules can be changed with a compiler "
"directive:"
msgstr "러스트가 어디서 모듈들을 찾을지는 컴파일러 디렉티브로 변경 가능합니다:"
#: src/modules/filesystem.md:54
msgid ""
"```rust,ignore\n"
"#[path = \"some/path.rs\"]\n"
"mod some_module;\n"
"```"
msgstr ""
"```rust,ignore\n"
"#[path = \"some/path.rs\"]\n"
"mod some_module;\n"
"```"
#: src/modules/filesystem.md:59
msgid ""
"This is useful, for example, if you would like to place tests for a module "
"in a file named `some_module_test.rs`, similar to the convention in Go."
msgstr ""
"이는 Go언어 에서처럼 어떤 모듈의 테스트를 `some_module_test.rs` 같은 파일에 "
"두고 싶은 경우에 유용합니다."
#: src/exercises/day-2/afternoon.md:1
msgid "Day 2: Afternoon Exercises"
msgstr "2일차 오후 연습문제"
#: src/exercises/day-2/afternoon.md:3
msgid "The exercises for this afternoon will focus on strings and iterators."
msgstr "이번 연습문제는 문자열과 반복자에 초점을 맞출 것입니다."
#: src/exercises/day-2/luhn.md:3
msgid ""
"The [Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) is used "
"to validate credit card numbers. The algorithm takes a string as input and "
"does the following to validate the credit card number:"
msgstr ""
"[룬(Luhn) 알고리즘](https://ko.wikipedia.org/wiki/"
"%EB%A3%AC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98)은 신용카드 번호 검증에 사용되"
"는 알고리즘 입니다. 이 알고리즘은 신용카드 번호를 `문자열`로 입력받고, 아래"
"의 순서에 따라 신용카드 번호의 유효성을 확인합니다:"
#: src/exercises/day-2/luhn.md:7
msgid "Ignore all spaces. Reject number with less than two digits."
msgstr "모든 공백을 무시합니다. 2자리 미만 숫자는 무시합니다."
#: src/exercises/day-2/luhn.md:9
msgid ""
"Moving from **right to left**, double every second digit: for the number "
"`1234`, we double `3` and `1`. For the number `98765`, we double `6` and `8`."
msgstr ""
"**오른쪽에서 왼쪽으로** 이동하며 2번째 자리마다 숫자를 2배 증가시킵니다. 예"
"를 들어 `1234`에서 `3`과 `1`에 각각 2를 곱합니다."
#: src/exercises/day-2/luhn.md:12
msgid ""
"After doubling a digit, sum the digits. So doubling `7` becomes `14` which "
"becomes `5`."
msgstr ""
"두배로 만든 숫자가 2자리라면 각 자리 숫자를 더합니다. 예를 들어, `7`은 두배"
"로 만들면 `14`이므로 `5`가 됩니다."
#: src/exercises/day-2/luhn.md:15
msgid "Sum all the undoubled and doubled digits."
msgstr "모든 자리의 숫자를 더합니다."
#: src/exercises/day-2/luhn.md:17
msgid "The credit card number is valid if the sum ends with `0`."
msgstr "합계의 끝자리가 `0`인 경우 유효한 신용카드 번호입니다."
#: src/exercises/day-2/luhn.md:19
msgid ""
"Copy the code below to <https://play.rust-lang.org/> and implement the "
"function."
msgstr ""
"아래 코드를 <https://play.rust-lang.org/>에 복사해서 구현하시면 됩니다."
#: src/exercises/day-2/luhn.md:21
msgid ""
"Try to solve the problem the \"simple\" way first, using `for` loops and "
"integers. Then, revisit the solution and try to implement it with iterators."
msgstr ""
"`for`반복문과 인덱스를 이용하는 \"쉬운\"방법으로 먼저 풀어 보세요. 그런 다음 "
"반복자를 이용해서 다시 풀어 보세요."
#: src/exercises/day-2/luhn.md:25
msgid ""
"```rust\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub fn luhn(cc_number: &str) -> bool {\n"
" unimplemented!()\n"
"}\n"
"\n"
"#[test]\n"
"fn test_non_digit_cc_number() {\n"
" assert!(!luhn(\"foo\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_empty_cc_number() {\n"
" assert!(!luhn(\"\"));\n"
" assert!(!luhn(\" \"));\n"
" assert!(!luhn(\" \"));\n"
" assert!(!luhn(\" \"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_single_digit_cc_number() {\n"
" assert!(!luhn(\"0\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_two_digit_cc_number() {\n"
" assert!(luhn(\" 0 0 \"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_valid_cc_number() {\n"
" assert!(luhn(\"4263 9826 4026 9299\"));\n"
" assert!(luhn(\"4539 3195 0343 6467\"));\n"
" assert!(luhn(\"7992 7398 713\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_invalid_cc_number() {\n"
" assert!(!luhn(\"4223 9826 4026 9299\"));\n"
" assert!(!luhn(\"4539 3195 0343 6476\"));\n"
" assert!(!luhn(\"8273 1232 7352 0569\"));\n"
"}\n"
"\n"
"#[allow(dead_code)]\n"
"fn main() {}\n"
"```"
msgstr ""
"```rust\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub fn luhn(cc_number: &str) -> bool {\n"
" unimplemented!()\n"
"}\n"
"\n"
"#[test]\n"
"fn test_non_digit_cc_number() {\n"
" assert!(!luhn(\"foo\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_empty_cc_number() {\n"
" assert!(!luhn(\"\"));\n"
" assert!(!luhn(\" \"));\n"
" assert!(!luhn(\" \"));\n"
" assert!(!luhn(\" \"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_single_digit_cc_number() {\n"
" assert!(!luhn(\"0\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_two_digit_cc_number() {\n"
" assert!(luhn(\" 0 0 \"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_valid_cc_number() {\n"
" assert!(luhn(\"4263 9826 4026 9299\"));\n"
" assert!(luhn(\"4539 3195 0343 6467\"));\n"
" assert!(luhn(\"7992 7398 713\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_invalid_cc_number() {\n"
" assert!(!luhn(\"4223 9826 4026 9299\"));\n"
" assert!(!luhn(\"4539 3195 0343 6476\"));\n"
" assert!(!luhn(\"8273 1232 7352 0569\"));\n"
"}\n"
"\n"
"#[allow(dead_code)]\n"
"fn main() {}\n"
"```"
#: src/exercises/day-2/strings-iterators.md:3
msgid ""
"In this exercise, you are implementing a routing component of a web server. "
"The server is configured with a number of _path prefixes_ which are matched "
"against _request paths_. The path prefixes can contain a wildcard character "
"which matches a full segment. See the unit tests below."
msgstr ""
"이번 훈련은 웹 서버의 라우팅 컴포넌트를 구현합니다. 서버는 _요청 경로"
"(request path)_ 를 처리할 수 있는 여러 개의 _경로 접두사(path prefix)_ 로 구"
"성됩니다. 경로 접두사는 와일드카드문자를 포함할 수 있습니다. 아래 단위 테스"
"트 코드를 참조하세요."
#: src/exercises/day-2/strings-iterators.md:8
msgid ""
"Copy the following code to <https://play.rust-lang.org/> and make the tests "
"pass. Try avoiding allocating a `Vec` for your intermediate results:"
msgstr ""
"아래 코드를 <https://play.rust-lang.org/>에 복사하고 테스트를 통과해 보시기 "
"바랍니다. 중간 결과값을 `Vec`에 할당하지 않도록 주의 하시기 바랍니다:"
#: src/exercises/day-2/strings-iterators.md:12
msgid ""
"```rust\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {\n"
" unimplemented!()\n"
"}\n"
"\n"
"#[test]\n"
"fn test_matches_without_wildcard() {\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers\"));\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/"
"abc-123\"));\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/abc/"
"books\"));\n"
"\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1\"));\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/publishersBooks\"));\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/parent/"
"publishers\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_matches_with_wildcard() {\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/books\"\n"
" ));\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/bar/books\"\n"
" ));\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/books/book1\"\n"
" ));\n"
"\n"
" assert!(!prefix_matches(\"/v1/publishers/*/books\", \"/v1/"
"publishers\"));\n"
" assert!(!prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/booksByAuthor\"\n"
" ));\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_variables, dead_code)]\n"
"\n"
"pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {\n"
" unimplemented!()\n"
"}\n"
"\n"
"#[test]\n"
"fn test_matches_without_wildcard() {\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers\"));\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/"
"abc-123\"));\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/abc/"
"books\"));\n"
"\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1\"));\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/publishersBooks\"));\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/parent/"
"publishers\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_matches_with_wildcard() {\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/books\"\n"
" ));\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/bar/books\"\n"
" ));\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/books/book1\"\n"
" ));\n"
"\n"
" assert!(!prefix_matches(\"/v1/publishers/*/books\", \"/v1/"
"publishers\"));\n"
" assert!(!prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/booksByAuthor\"\n"
" ));\n"
"}\n"
"```"
#: src/welcome-day-3.md:1
msgid "Welcome to Day 3"
msgstr "3일차 개요"
#: src/welcome-day-3.md:3
msgid "Today, we will cover some more advanced topics of Rust:"
msgstr "오늘은 몇 가지 고급 주제를 다룹니다:"
#: src/welcome-day-3.md:5
msgid ""
"Traits: deriving traits, default methods, and important standard library "
"traits."
msgstr ""
"트레잇: 트레잇 상속(derive), 디폴트 메서드, 표준 라이브러에 있는 중요한 트레"
"잇들."
#: src/welcome-day-3.md:8
msgid ""
"Generics: generic data types, generic methods, monomorphization, and trait "
"objects."
msgstr ""
"제네릭: 제네릭 데이터 타입, 제네릭 메서드, 단형화(monomorphization), 트레잇 "
"객체."
#: src/welcome-day-3.md:11
msgid "Error handling: panics, `Result`, and the try operator `?`."
msgstr "오류처리(에러 핸들링): 패닉, `Result`, `?` 연산자."
#: src/welcome-day-3.md:13
msgid "Testing: unit tests, documentation tests, and integration tests."
msgstr "테스트: 단위 테스트, 문서 테스트 및 통합 테스트."
#: src/welcome-day-3.md:15
msgid ""
"Unsafe Rust: raw pointers, static variables, unsafe functions, and extern "
"functions."
msgstr ""
"안전하지 않은 러스트: 원시(raw) 포인터, 정적 변수, 안전하지 않은 함수, 외부 "
"함수."
#: src/generics.md:3
msgid ""
"Rust support generics, which lets you abstract algorithms or data structures "
"(such as sorting or a binary tree) over the types used or stored."
msgstr ""
"러스트는 제네릭을 지원합니다. 이를 이용하면 알고리즘(정렬과 같은)이나 데이터 "
"구조(이진 트리 같은)를 추상화 하여 특정 타입에 의존하지 않도록 할 수 있습니"
"다."
#: src/generics/data-types.md:3
msgid "You can use generics to abstract over the concrete field type:"
msgstr "제네릭을 사용하여 필드의 타입을 추상화 할 수 있습니다:"
#: src/generics/data-types.md:5
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point<T> {\n"
" x: T,\n"
" y: T,\n"
"}\n"
"\n"
"fn main() {\n"
" let integer = Point { x: 5, y: 10 };\n"
" let float = Point { x: 1.0, y: 4.0 };\n"
" println!(\"{integer:?} and {float:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point<T> {\n"
" x: T,\n"
" y: T,\n"
"}\n"
"\n"
"fn main() {\n"
" let integer = Point { x: 5, y: 10 };\n"
" let float = Point { x: 1.0, y: 4.0 };\n"
" println!(\"{integer:?} and {float:?}\");\n"
"}\n"
"```"
#: src/generics/data-types.md:21
msgid "Try declaring a new variable `let p = Point { x: 5, y: 10.0 };`."
msgstr "새 변수 `let p = Point { x: 5, y: 10.0 };`를 선언해 보세요."
#: src/generics/data-types.md:23
msgid "Fix the code to allow points that have elements of different types."
msgstr ""
"`Point`가 서로 다른 타입의 값들으로 이루어져도 컴파일 되도록 코드를 수정해 보"
"세요."
#: src/generics/methods.md:3
msgid "You can declare a generic type on your `impl` block:"
msgstr "`impl` 블록에서도 제네릭 타입을 선언할 수 있습니다:"
#: src/generics/methods.md:5
msgid ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point<T>(T, T);\n"
"\n"
"impl<T> Point<T> {\n"
" fn x(&self) -> &T {\n"
" &self.0 // + 10\n"
" }\n"
"\n"
" // fn set_x(&mut self, x: T)\n"
"}\n"
"\n"
"fn main() {\n"
" let p = Point(5, 10);\n"
" println!(\"p.x = {}\", p.x());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug)]\n"
"struct Point<T>(T, T);\n"
"\n"
"impl<T> Point<T> {\n"
" fn x(&self) -> &T {\n"
" &self.0 // + 10\n"
" }\n"
"\n"
" // fn set_x(&mut self, x: T)\n"
"}\n"
"\n"
"fn main() {\n"
" let p = Point(5, 10);\n"
" println!(\"p.x = {}\", p.x());\n"
"}\n"
"```"
#: src/generics/methods.md:25
msgid ""
"_Q:_ Why `T` is specified twice in `impl<T> Point<T> {}`? Isn't that "
"redundant?"
msgstr "_질문:_ `impl<T> Point<T> {}`에서 `T`가 왜 두 번 사용됩니까?"
#: src/generics/methods.md:26
msgid ""
"This is because it is a generic implementation section for generic type. "
"They are independently generic."
msgstr ""
"제네릭 타입에 대한 제네릭 구현 이기 때문입니다. 이 두 제네릭은 서로 독립적입"
"니다."
#: src/generics/methods.md:27
msgid "It means these methods are defined for any `T`."
msgstr ""
"이는 임의의 모든 `T`에 대해서 이 메소드들이 정의된다는 것을 의미합니다."
#: src/generics/methods.md:28
msgid "It is possible to write `impl Point<u32> { .. }`. "
msgstr "`impl Point<u32> { .. }`와 같이 작성하는 것도 가능합니다. "
#: src/generics/methods.md:29
msgid ""
"`Point` is still generic and you can use `Point<f64>`, but methods in this "
"block will only be available for `Point<u32>`."
msgstr ""
"`Point`는 여전히 제네릭이며 `Point<f64>`를 사용할 수도 있지만 이 블록의 메서"
"드는 `Point<u32>`만 쓸 수 있습니다."
#: src/generics/monomorphization.md:3
msgid "Generic code is turned into non-generic code based on the call sites:"
msgstr "제네릭 코드는 호출부에서 비 제네릭 코드로 전환됩니다:"
#: src/generics/monomorphization.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let integer = Some(5);\n"
" let float = Some(5.0);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let integer = Some(5);\n"
" let float = Some(5.0);\n"
"}\n"
"```"
#: src/generics/monomorphization.md:12
msgid "behaves as if you wrote"
msgstr "위 코드는 아래와 같이 동작합니다"
#: src/generics/monomorphization.md:14
msgid ""
"```rust,editable\n"
"enum Option_i32 {\n"
" Some(i32),\n"
" None,\n"
"}\n"
"\n"
"enum Option_f64 {\n"
" Some(f64),\n"
" None,\n"
"}\n"
"\n"
"fn main() {\n"
" let integer = Option_i32::Some(5);\n"
" let float = Option_f64::Some(5.0);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"enum Option_i32 {\n"
" Some(i32),\n"
" None,\n"
"}\n"
"\n"
"enum Option_f64 {\n"
" Some(f64),\n"
" None,\n"
"}\n"
"\n"
"fn main() {\n"
" let integer = Option_i32::Some(5);\n"
" let float = Option_f64::Some(5.0);\n"
"}\n"
"```"
#: src/generics/monomorphization.md:31
msgid ""
"This is a zero-cost abstraction: you get exactly the same result as if you "
"had hand-coded the data structures without the abstraction."
msgstr ""
"이것이 바로 비용이 들지 않는 (zero-cost) 추상화 입니다: 러스트의 제네릭은 추"
"상화를 거치지 않고 직접 구체적인 타입을 써서 코딩한 것과 정확히 동일한 결과"
"를 보여줍니다."
#: src/traits.md:3
msgid ""
"Rust lets you abstract over types with traits. They're similar to interfaces:"
msgstr "트레잇은 타입을 추상화 하는데 사용됩니다. 인터페이스와 비슷합니다:"
#: src/traits.md:5
msgid ""
"```rust,editable\n"
"trait Pet {\n"
" fn name(&self) -> String;\n"
"}\n"
"\n"
"struct Dog {\n"
" name: String,\n"
"}\n"
"\n"
"struct Cat;\n"
"\n"
"impl Pet for Dog {\n"
" fn name(&self) -> String {\n"
" self.name.clone()\n"
" }\n"
"}\n"
"\n"
"impl Pet for Cat {\n"
" fn name(&self) -> String {\n"
" String::from(\"The cat\") // No name, cats won't respond to it "
"anyway.\n"
" }\n"
"}\n"
"\n"
"fn greet<P: Pet>(pet: &P) {\n"
" println!(\"Who's a cutie? {} is!\", pet.name());\n"
"}\n"
"\n"
"fn main() {\n"
" let fido = Dog { name: \"Fido\".into() };\n"
" greet(&fido);\n"
"\n"
" let captain_floof = Cat;\n"
" greet(&captain_floof);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"trait Pet {\n"
" fn name(&self) -> String;\n"
"}\n"
"\n"
"struct Dog {\n"
" name: String,\n"
"}\n"
"\n"
"struct Cat;\n"
"\n"
"impl Pet for Dog {\n"
" fn name(&self) -> String {\n"
" self.name.clone()\n"
" }\n"
"}\n"
"\n"
"impl Pet for Cat {\n"
" fn name(&self) -> String {\n"
" String::from(\"The cat\") // No name, cats won't respond to it "
"anyway.\n"
" }\n"
"}\n"
"\n"
"fn greet<P: Pet>(pet: &P) {\n"
" println!(\"Who's a cutie? {} is!\", pet.name());\n"
"}\n"
"\n"
"fn main() {\n"
" let fido = Dog { name: \"Fido\".into() };\n"
" greet(&fido);\n"
"\n"
" let captain_floof = Cat;\n"
" greet(&captain_floof);\n"
"}\n"
"```"
#: src/traits/trait-objects.md:3
msgid ""
"Trait objects allow for values of different types, for instance in a "
"collection:"
msgstr ""
"트레잇 객체는 타입이 다른 값(예를 들어 컬렉션에 속한 각 값)들을 가질 수 있습"
"니다:"
#: src/traits/trait-objects.md:5
msgid ""
"```rust,editable\n"
"trait Pet {\n"
" fn name(&self) -> String;\n"
"}\n"
"\n"
"struct Dog {\n"
" name: String,\n"
"}\n"
"\n"
"struct Cat;\n"
"\n"
"impl Pet for Dog {\n"
" fn name(&self) -> String {\n"
" self.name.clone()\n"
" }\n"
"}\n"
"\n"
"impl Pet for Cat {\n"
" fn name(&self) -> String {\n"
" String::from(\"The cat\") // No name, cats won't respond to it "
"anyway.\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let pets: Vec<Box<dyn Pet>> = vec![\n"
" Box::new(Cat),\n"
" Box::new(Dog { name: String::from(\"Fido\") }),\n"
" ];\n"
" for pet in pets {\n"
" println!(\"Hello {}!\", pet.name());\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"trait Pet {\n"
" fn name(&self) -> String;\n"
"}\n"
"\n"
"struct Dog {\n"
" name: String,\n"
"}\n"
"\n"
"struct Cat;\n"
"\n"
"impl Pet for Dog {\n"
" fn name(&self) -> String {\n"
" self.name.clone()\n"
" }\n"
"}\n"
"\n"
"impl Pet for Cat {\n"
" fn name(&self) -> String {\n"
" String::from(\"The cat\") // No name, cats won't respond to it "
"anyway.\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let pets: Vec<Box<dyn Pet>> = vec![\n"
" Box::new(Cat),\n"
" Box::new(Dog { name: String::from(\"Fido\") }),\n"
" ];\n"
" for pet in pets {\n"
" println!(\"Hello {}!\", pet.name());\n"
" }\n"
"}\n"
"```"
#: src/traits/trait-objects.md:40
msgid "Memory layout after allocating `pets`:"
msgstr "`pets`를 할당한 이후의 메모리 레이아웃:"
#: src/traits/trait-objects.md:42
msgid ""
"```bob\n"
" Stack Heap\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - "
"- -.\n"
": : : :\n"
": "
"pets : : :\n"
": +-----------+-------+ : : +-----+-----"
"+ :\n"
": | ptr | o---+---+-----+-->| o o | o o "
"| :\n"
": | len | 2 | : : +-|-|-+-|-|-"
"+ :\n"
": | capacity | 2 | : : | | | | +---------------"
"+ :\n"
": +-----------+-------+ : : | | | '-->| name: \"Fido\" "
"| :\n"
": : : | | | +---------------"
"+ :\n"
"`- - - - - - - - - - - - - -' : | | "
"| :\n"
" : | | | +----------------------"
"+ : \n"
" : | | '---->| \"<Dog as Pet>::name\" "
"| :\n"
" : | | +----------------------"
"+ : \n"
" : | "
"| : \n"
" : | | +-"
"+ : \n"
" : | '-->|"
"\\| : \n"
" : | +-"
"+ : \n"
" : "
"| : \n"
" : | +----------------------"
"+ : \n"
" : '---->| \"<Cat as Pet>::name\" "
"| : \n"
" : +----------------------"
"+ :\n"
" : :\n"
" '- - - - - - - - - - - - - - - - - - - - - "
"- -'\n"
"\n"
"```"
msgstr ""
"```bob\n"
" 스택 힙\n"
".- - - - - - - - - - - - - -. .- - - - - - - - - - - - - - - - - - - - - "
"- -.\n"
": : : :\n"
": "
"pets : : :\n"
": +-----------+-------+ : : +-----+-----"
"+ :\n"
": | ptr | o---+---+-----+-->| o o | o o "
"| :\n"
": | len | 2 | : : +-|-|-+-|-|-"
"+ :\n"
": | capacity | 2 | : : | | | | +---------------"
"+ :\n"
": +-----------+-------+ : : | | | '-->| name: \"Fido\" "
"| :\n"
": : : | | | +---------------"
"+ :\n"
"`- - - - - - - - - - - - - -' : | | "
"| :\n"
" : | | | +----------------------"
"+ : \n"
" : | | '---->| \"<Dog as Pet>::name\" "
"| :\n"
" : | | +----------------------"
"+ : \n"
" : | "
"| : \n"
" : | | +-"
"+ : \n"
" : | '-->|"
"\\| : \n"
" : | +-"
"+ : \n"
" : "
"| : \n"
" : | +----------------------"
"+ : \n"
" : '---->| \"<Cat as Pet>::name\" "
"| : \n"
" : +----------------------"
"+ :\n"
" : :\n"
" '- - - - - - - - - - - - - - - - - - - - - "
"- -'\n"
"\n"
"```"
#: src/traits/trait-objects.md:72
msgid ""
"Types that implement a given trait may be of different sizes. This makes it "
"impossible to have things like `Vec<Pet>` in the example above."
msgstr ""
"여러 타입이 같은 트레잇을 구현하더라도 그 크기는 서로 다를 수 있습니다. 그래"
"서 `Vec<Greeet>`같은 것은 불가능합니다."
#: src/traits/trait-objects.md:73
msgid ""
"`dyn Pet` is a way to tell the compiler about a dynamically sized type that "
"implements `Pet`."
msgstr ""
"`dyn Pet`이라고 하면이 타입의 크기는 동적이며 `Pet`을 구현하고 있다고 컴파일"
"러에게 알려주는 것입니다."
#: src/traits/trait-objects.md:74
msgid ""
"In the example, `pets` holds _fat pointers_ to objects that implement `Pet`. "
"The fat pointer consists of two components, a pointer to the actual object "
"and a pointer to the virtual method table for the `Pet` implementation of "
"that particular object."
msgstr ""
"예제에서 `pets`는 `Pet`을 구현하는 객체들의 _Fat 포인터_를 담고 있습니다. "
"Fat 포인터는 실제 객체에 대한 포인터와 그 객체가 `Pet`을 구현하고 있는 가상 "
"함수 테이블에 대한 포인터를 가집니다."
#: src/traits/trait-objects.md:75
msgid "Compare these outputs in the above example:"
msgstr "아래 코드의 결과와 비교해보세요:"
#: src/traits/trait-objects.md:76
msgid ""
"```rust,ignore\n"
" println!(\"{} {}\", std::mem::size_of::<Dog>(), std::mem::size_of::"
"<Cat>());\n"
" println!(\"{} {}\", std::mem::size_of::<&Dog>(), std::mem::size_of::"
"<&Cat>());\n"
" println!(\"{}\", std::mem::size_of::<&dyn Pet>());\n"
" println!(\"{}\", std::mem::size_of::<Box<dyn Pet>>());\n"
"```"
msgstr ""
"```rust,ignore\n"
" println!(\"{} {}\", std::mem::size_of::<Dog>(), std::mem::size_of::"
"<Cat>());\n"
" println!(\"{} {}\", std::mem::size_of::<&Dog>(), std::mem::size_of::"
"<&Cat>());\n"
" println!(\"{}\", std::mem::size_of::<&dyn Pet>());\n"
" println!(\"{}\", std::mem::size_of::<Box<dyn Pet>>());\n"
"```"
#: src/traits/deriving-traits.md:3
msgid ""
"Rust derive macros work by automatically generating code that implements the "
"specified traits for a data structure."
msgstr ""
"러스트의 derive 매크로는 데이터 구조체가 특정 트레잇을 구현하는 코드를 자동으"
"로 만들어 줍니다."
#: src/traits/deriving-traits.md:5
msgid "You can let the compiler derive a number of traits as follows:"
msgstr ""
"컴파일러가 여러가지 트레잇을 상속(derive)하도록 할 수 있습니다. 이 경우 컴파"
"일러가 트레잇을 자동으로 구현합니다:"
#: src/traits/deriving-traits.md:7
msgid ""
"```rust,editable\n"
"#[derive(Debug, Clone, PartialEq, Eq, Default)]\n"
"struct Player {\n"
" name: String,\n"
" strength: u8,\n"
" hit_points: u8,\n"
"}\n"
"\n"
"fn main() {\n"
" let p1 = Player::default();\n"
" let p2 = p1.clone();\n"
" println!(\"Is {:?}\\nequal to {:?}?\\nThe answer is {}!\", &p1, &p2,\n"
" if p1 == p2 { \"yes\" } else { \"no\" });\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug, Clone, PartialEq, Eq, Default)]\n"
"struct Player {\n"
" name: String,\n"
" strength: u8,\n"
" hit_points: u8,\n"
"}\n"
"\n"
"fn main() {\n"
" let p1 = Player::default();\n"
" let p2 = p1.clone();\n"
" println!(\"Is {:?}\\nequal to {:?}?\\nThe answer is {}!\", &p1, &p2,\n"
" if p1 == p2 { \"yes\" } else { \"no\" });\n"
"}\n"
"```"
#: src/traits/default-methods.md:3
msgid "Traits can implement behavior in terms of other trait methods:"
msgstr ""
"트레잇의 디폴트 메서드에서 다른(구현되지 않은) 메소드를 이용할 수 있습니다:"
#: src/traits/default-methods.md:5
msgid ""
"```rust,editable\n"
"trait Equals {\n"
" fn equals(&self, other: &Self) -> bool;\n"
" fn not_equals(&self, other: &Self) -> bool {\n"
" !self.equals(other)\n"
" }\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"struct Centimeter(i16);\n"
"\n"
"impl Equals for Centimeter {\n"
" fn equals(&self, other: &Centimeter) -> bool {\n"
" self.0 == other.0\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let a = Centimeter(10);\n"
" let b = Centimeter(20);\n"
" println!(\"{a:?} equals {b:?}: {}\", a.equals(&b));\n"
" println!(\"{a:?} not_equals {b:?}: {}\", a.not_equals(&b));\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"trait Equals {\n"
" fn equals(&self, other: &Self) -> bool;\n"
" fn not_equals(&self, other: &Self) -> bool {\n"
" !self.equals(other)\n"
" }\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"struct Centimeter(i16);\n"
"\n"
"impl Equals for Centimeter {\n"
" fn equals(&self, other: &Centimeter) -> bool {\n"
" self.0 == other.0\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let a = Centimeter(10);\n"
" let b = Centimeter(20);\n"
" println!(\"{a:?} equals {b:?}: {}\", a.equals(&b));\n"
" println!(\"{a:?} not_equals {b:?}: {}\", a.not_equals(&b));\n"
"}\n"
"```"
#: src/traits/default-methods.md:32
msgid ""
"Traits may specify pre-implemented (default) methods and methods that users "
"are required to implement themselves. Methods with default implementations "
"can rely on required methods."
msgstr ""
"트레잇은, 그 트레잇이 정의된 위치에서 직접 구현되는 디폴트 메서드와, 거기에서"
"는 선언만 존재하고 그 트레잇을 구현하는 타입에서 구현해야 하는, 두 종류의 메"
"서드를 가질 수 있습니다. 디폴트 메서드를 구현할 때에는, 두 종류의 메서드 모"
"두 사용(호출)할 수 있습니다."
#: src/traits/default-methods.md:35
msgid "Move method `not_equals` to a new trait `NotEquals`."
msgstr "`not_equal` 메서드를 새로운 트레잇인 `NotEqual`로 이동합니다."
#: src/traits/default-methods.md:37
msgid "Make `Equals` a super trait for `NotEquals`."
msgstr "`NotEqual`을 `Equal`의 슈퍼 트레잇으로 만듭니다."
#: src/traits/default-methods.md:38
msgid ""
"```rust,editable,compile_fail\n"
"trait NotEquals: Equals {\n"
" fn not_equals(&self, other: &Self) -> bool {\n"
" !self.equals(other)\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"trait NotEquals: Equals {\n"
" fn not_equals(&self, other: &Self) -> bool {\n"
" !self.equals(other)\n"
" }\n"
"}\n"
"```"
#: src/traits/default-methods.md:46
msgid "Provide a blanket implementation of `NotEquals` for `Equals`."
msgstr "`Equal`에 `NotEqual`의 포괄적 구현을 제공합니다."
#: src/traits/default-methods.md:47
msgid ""
"```rust,editable,compile_fail\n"
"trait NotEquals {\n"
" fn not_equals(&self, other: &Self) -> bool;\n"
"}\n"
"\n"
"impl<T> NotEquals for T where T: Equals {\n"
" fn not_equals(&self, other: &Self) -> bool {\n"
" !self.equals(other)\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"trait NotEquals {\n"
" fn not_equals(&self, other: &Self) -> bool;\n"
"}\n"
"\n"
"impl<T> NotEquals for T where T: Equals {\n"
" fn not_equals(&self, other: &Self) -> bool {\n"
" !self.equals(other)\n"
" }\n"
"}\n"
"```"
#: src/traits/default-methods.md:58
msgid ""
"With the blanket implementation, you no longer need `Equals` as a super "
"trait for `NotEqual`."
msgstr ""
"포괄적 구현을 사용하면 더 이상 `NotEqual`이 `Equal`의 슈퍼 트레잇으로 필요하"
"지 않습니다."
#: src/traits/trait-bounds.md:3
msgid ""
"When working with generics, you often want to require the types to implement "
"some trait, so that you can call this trait's methods."
msgstr ""
"제네릭을 이용하다 보면 타입이 어떤 트레잇을 구현하고 있어야 하는 경우가 있습"
"니다. 그래야 그 트레잇의 메서드를 호출할 수 있기 때문입니다."
#: src/traits/trait-bounds.md:6
msgid "You can do this with `T: Trait` or `impl Trait`:"
msgstr "`T: Trait` 혹은 `impl Trait`를 사용하면 됩니다:"
#: src/traits/trait-bounds.md:8
msgid ""
"```rust,editable\n"
"fn duplicate<T: Clone>(a: T) -> (T, T) {\n"
" (a.clone(), a.clone())\n"
"}\n"
"\n"
"// Syntactic sugar for:\n"
"// fn add_42_millions<T: Into<i32>>(x: T) -> i32 {\n"
"fn add_42_millions(x: impl Into<i32>) -> i32 {\n"
" x.into() + 42_000_000\n"
"}\n"
"\n"
"// struct NotClonable;\n"
"\n"
"fn main() {\n"
" let foo = String::from(\"foo\");\n"
" let pair = duplicate(foo);\n"
" println!(\"{pair:?}\");\n"
"\n"
" let many = add_42_millions(42_i8);\n"
" println!(\"{many}\");\n"
" let many_more = add_42_millions(10_000_000);\n"
" println!(\"{many_more}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn duplicate<T: Clone>(a: T) -> (T, T) {\n"
" (a.clone(), a.clone())\n"
"}\n"
"\n"
"// 다음에 대한 문법 슈가:\n"
"// fn add_42_millions<T: Into<i32>>(x: T) -> i32 {\n"
"fn add_42_millions(x: impl Into<i32>) -> i32 {\n"
" x.into() + 42_000_000\n"
"}\n"
"\n"
"// struct NotClonable;\n"
"\n"
"fn main() {\n"
" let foo = String::from(\"foo\");\n"
" let pair = duplicate(foo);\n"
" println!(\"{pair:?}\");\n"
"\n"
" let many = add_42_millions(42_i8);\n"
" println!(\"{many}\");\n"
" let many_more = add_42_millions(10_000_000);\n"
" println!(\"{many_more}\");\n"
"}\n"
"```"
#: src/traits/trait-bounds.md:35
msgid "Show a `where` clause, students will encounter it when reading code."
msgstr ""
"`where` 문법을 사용할 수도 있습니다. 수강생들도 코드를 읽다가 그 문법을 마주"
"할 수 있습니다."
#: src/traits/trait-bounds.md:37
msgid ""
"```rust,ignore\n"
"fn duplicate<T>(a: T) -> (T, T)\n"
"where\n"
" T: Clone,\n"
"{\n"
" (a.clone(), a.clone())\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"fn duplicate<T>(a: T) -> (T, T)\n"
"where\n"
" T: Clone,\n"
"{\n"
" (a.clone(), a.clone())\n"
"}\n"
"```"
#: src/traits/trait-bounds.md:46
msgid "It declutters the function signature if you have many parameters."
msgstr ""
"이를 이용하면 타입 파라메터가 많은 경우 함수 시그니처를 간결하게 정리하는 데 "
"도움이 됩니다."
#: src/traits/trait-bounds.md:47
msgid "It has additional features making it more powerful."
msgstr "좀 더 강력한 추가 기능도 제공합니다."
#: src/traits/trait-bounds.md:48
msgid ""
"If someone asks, the extra feature is that the type on the left of \":\" can "
"be arbitrary, like `Option<T>`."
msgstr "`:` 왼쪽에 임의의 타입(예를 들어 `Option<T>`)을 사용할 수 있습니다."
#: src/traits/impl-trait.md:1
msgid "`impl Trait`"
msgstr "트레잇 구현하기(`impl Trait`)"
#: src/traits/impl-trait.md:3
msgid ""
"Similar to trait bounds, an `impl Trait` syntax can be used in function "
"arguments and return values:"
msgstr ""
"트레잇 바운드와 유사하게 `impl Trait` 문법은 함수의 인자와 반환값에도 적용 가"
"능합니다:"
#: src/traits/impl-trait.md:6
msgid ""
"```rust,editable\n"
"use std::fmt::Display;\n"
"\n"
"fn get_x(name: impl Display) -> impl Display {\n"
" format!(\"Hello {name}\")\n"
"}\n"
"\n"
"fn main() {\n"
" let x = get_x(\"foo\");\n"
" println!(\"{x}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::fmt::Display;\n"
"\n"
"fn get_x(name: impl Display) -> impl Display {\n"
" format!(\"Hello {name}\")\n"
"}\n"
"\n"
"fn main() {\n"
" let x = get_x(\"foo\");\n"
" println!(\"{x}\");\n"
"}\n"
"```"
#: src/traits/impl-trait.md:19
msgid "`impl Trait` allows you to work with types which you cannot name."
msgstr "`impl Trait`를 이용하면 이름이 없는 타입을 다룰 수 있습니다."
#: src/traits/impl-trait.md:23
msgid ""
"The meaning of `impl Trait` is a bit different in the different positions."
msgstr "`impl Trait`는 어디에 사용되었느냐에 따라 의미가 조금씩 다릅니다."
#: src/traits/impl-trait.md:25
msgid ""
"For a parameter, `impl Trait` is like an anonymous generic parameter with a "
"trait bound."
msgstr ""
"함수 인자의 타입으로 사용되었을 경우에는 `impl Trait`는 트레잇 경계가 있는 익"
"명의 제네릭 타입을 의미합니다."
#: src/traits/impl-trait.md:27
msgid ""
"For a return type, it means that the return type is some concrete type that "
"implements the trait, without naming the type. This can be useful when you "
"don't want to expose the concrete type in a public API."
msgstr ""
"리턴 타입으로 사용되었을 경우에는, 그 트레잇을 구현하는 구체적인 타입인데, 타"
"입 이름을 프로그래머가 짓지 않았다는 것을 의미합니다. 이는 그 구체적인 타입 "
"이름을 API로 공개하고 싶지 않은 경우에 유용합니다."
#: src/traits/impl-trait.md:31
msgid ""
"Inference is hard in return position. A function returning `impl Foo` picks "
"the concrete type it returns, without writing it out in the source. A "
"function returning a generic type like `collect<B>() -> B` can return any "
"type satisfying `B`, and the caller may need to choose one, such as with "
"`let x: Vec<_> = foo.collect()` or with the turbofish, `foo.collect::"
"<Vec<_>>()`."
msgstr ""
"함수가 리턴되는 곳에서의 타입 추론은 어렵습니다. 어떤 함수의 리턴 타입이 "
"`impl Foo`로 선언되어 있을 경우, 그 함수가 실제로 리턴하는 타입은 소스 코드 "
"상 어디에도 나타나 있지 않습니다. `collect<B<() -> B`와 같이 제너릭 타입을 리"
"턴하는 함수는 `B`를 만족하는 어떤 타입도 리턴할 수 있습니다. 이 경우, 호출하"
"는 측에서는 `let x: Vec<_> = foo.collect()`나 터보피시 문법을 써서 `foo."
"collect::<Vec<_>>()`와 같이 리턴 타입을 명시적으로 써 주어야 할 수도 있습니"
"다."
#: src/traits/impl-trait.md:37
msgid ""
"This example is great, because it uses `impl Display` twice. It helps to "
"explain that nothing here enforces that it is _the same_ `impl Display` "
"type. If we used a single `T: Display`, it would enforce the constraint "
"that input `T` and return `T` type are the same type. It would not work for "
"this particular function, as the type we expect as input is likely not what "
"`format!` returns. If we wanted to do the same via `: Display` syntax, we'd "
"need two independent generic parameters."
msgstr ""
"이 예시는 `impl Display`가 두번 사용 되었다는 점에서 훌륭합니다. 여기서 중요"
"한 것은 이 두 `impl Display`가 실제로 같은 타입일 필요가 없다는 것입니다. 만"
"약 `T: Display`로 트레잇 경계를 정하고 입력 파라메터와 리턴 값의 타입을 모두 "
"`T`로 했다면, 이는 입력과 리턴값이 같은 타입임을 강제합니다. 이렇게 했다면 위"
"의 예제는 동작하지 않았을 것입니다. 왜냐하면, 입력 값의 타입이 `format!`이 리"
"턴하는 타입과 같지 않을 가능성이 높기 때문입니다. 만약 `: Display` 문법을 사"
"용하고 싶다면 독립적인 제네릭 매개변수가 두 개가 필요합니다."
#: src/traits/important-traits.md:3
msgid ""
"We will now look at some of the most common traits of the Rust standard "
"library:"
msgstr ""
"러스트 표준 라이브러리에는 다음과 같은 범용 트레잇들이 정의되어 있습니다:"
#: src/traits/important-traits.md:5
msgid ""
"[`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) and "
"[`IntoIterator`](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html) "
"used in `for` loops,"
msgstr ""
"[`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html)와 "
"[`IntoIterator`](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html) "
"트레잇은 `for` 반복문에서 사용됩니다,"
#: src/traits/important-traits.md:6
msgid ""
"[`From`](https://doc.rust-lang.org/std/convert/trait.From.html) and [`Into`]"
"(https://doc.rust-lang.org/std/convert/trait.Into.html) used to convert "
"values,"
msgstr ""
"[`From`](https://doc.rust-lang.org/std/convert/trait.From.html)과 [`Into`]"
"(https://doc.rust-lang.org/std/convert/trait.Into.html) 트레잇은 값을 변환할 "
"때 사용됩니다,"
#: src/traits/important-traits.md:7
msgid ""
"[`Read`](https://doc.rust-lang.org/std/io/trait.Read.html) and [`Write`]"
"(https://doc.rust-lang.org/std/io/trait.Write.html) used for IO,"
msgstr ""
"[`Read`](https://doc.rust-lang.org/std/io/trait.Read.html)와 [`Write`]"
"(https://doc.rust-lang.org/std/io/trait.Write.html) 트레잇은 I/O에 사용됩니"
"다,"
#: src/traits/important-traits.md:8
msgid ""
"[`Add`](https://doc.rust-lang.org/std/ops/trait.Add.html), [`Mul`](https://"
"doc.rust-lang.org/std/ops/trait.Mul.html), ... used for operator "
"overloading, and"
msgstr ""
"[`Add`](https://doc.rust-lang.org/std/ops/trait.Add.html), [`Mul`](https://"
"doc.rust-lang.org/std/ops/trait.Mul.html) 등의 트레잇들은 연산자 오버로딩"
"(overloading)에 사용됩니다."
#: src/traits/important-traits.md:9
msgid ""
"[`Drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html) used for "
"defining destructors."
msgstr ""
"[`Drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html) 트레잇은 소멸자 "
"정의에 사용됩니다."
#: src/traits/important-traits.md:10
msgid ""
"[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) used "
"to construct a default instance of a type."
msgstr ""
"[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) 트레잇"
"은 어떤 타입의 기본값 인스턴스를 만들때 사용됩니다."
#: src/traits/iterator.md:1
msgid "Iterators"
msgstr "Iterators"
#: src/traits/iterator.md:3
msgid ""
"You can implement the [`Iterator`](https://doc.rust-lang.org/std/iter/trait."
"Iterator.html) trait on your own types:"
msgstr "`Iterator`트레잇을 여러분이 정의한 타입에서 구현해 보겠습니다:"
#: src/traits/iterator.md:5
msgid ""
"```rust,editable\n"
"struct Fibonacci {\n"
" curr: u32,\n"
" next: u32,\n"
"}\n"
"\n"
"impl Iterator for Fibonacci {\n"
" type Item = u32;\n"
"\n"
" fn next(&mut self) -> Option<Self::Item> {\n"
" let new_next = self.curr + self.next;\n"
" self.curr = self.next;\n"
" self.next = new_next;\n"
" Some(self.curr)\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let fib = Fibonacci { curr: 0, next: 1 };\n"
" for (i, n) in fib.enumerate().take(5) {\n"
" println!(\"fib({i}): {n}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"struct Fibonacci {\n"
" curr: u32,\n"
" next: u32,\n"
"}\n"
"\n"
"impl Iterator for Fibonacci {\n"
" type Item = u32;\n"
"\n"
" fn next(&mut self) -> Option<Self::Item> {\n"
" let new_next = self.curr + self.next;\n"
" self.curr = self.next;\n"
" self.next = new_next;\n"
" Some(self.curr)\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let fib = Fibonacci { curr: 0, next: 1 };\n"
" for (i, n) in fib.enumerate().take(5) {\n"
" println!(\"fib({i}): {n}\");\n"
" }\n"
"}\n"
"```"
#: src/traits/iterator.md:32
msgid ""
"The `Iterator` trait implements many common functional programming "
"operations over collections (e.g. `map`, `filter`, `reduce`, etc). This is "
"the trait where you can find all the documentation about them. In Rust these "
"functions should produce the code as efficient as equivalent imperative "
"implementations."
msgstr ""
"`Iterator` 트레잇은 컬렉션에 대한 여러 일반적인 함수 프로그래밍 작업(예: "
"`map`, `filter`, `reduce` 등)을 구현합니다. 이는 관련 문서를 모두 찾을 수 있"
"는 트레잇입니다. Rust에서는 이러한 함수가, 이와 동일한 일을 하는 명령형 구현"
"만큼 효율적인 코드를 생성합니다."
#: src/traits/iterator.md:37
msgid ""
"`IntoIterator` is the trait that makes for loops work. It is implemented by "
"collection types such as `Vec<T>` and references to them such as `&Vec<T>` "
"and `&[T]`. Ranges also implement it. This is why you can iterate over a "
"vector with `for i in some_vec { .. }` but `some_vec.next()` doesn't exist."
msgstr ""
"`IntoIterator`는 루프를 작동하게 만드는 트레잇입니다. 이는 `Vec<T>`와 같은 컬"
"렉션 유형과 `&Vec<T>` 및 `&[T]`와 같은 이에 대한 참조에 의해 구현됩니다. 범위"
"도 이를 구현합니다. 이런 이유로 `for i in some_vec { .. }`를 사용하여 벡터를 "
"반복할 수 있지만 `some_vec.next()`는 존재하지 않습니다."
#: src/traits/from-iterator.md:3
msgid ""
"[`FromIterator`](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) "
"lets you build a collection from an [`Iterator`](https://doc.rust-lang.org/"
"std/iter/trait.Iterator.html)."
msgstr ""
"어떤 컬렉션이 [`FromIterator`](https://doc.rust-lang.org/std/iter/trait."
"FromIterator.html)를 구현하고 있다면 [`Iterator`](https://doc.rust-lang.org/"
"std/iter/trait.Iterator.html)로부터 그 컬렉션을 만들 수 있습니다."
#: src/traits/from-iterator.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let primes = vec![2, 3, 5, 7];\n"
" let prime_squares = primes\n"
" .into_iter()\n"
" .map(|prime| prime * prime)\n"
" .collect::<Vec<_>>();\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let primes = vec![2, 3, 5, 7];\n"
" let prime_squares = primes\n"
" .into_iter()\n"
" .map(|prime| prime * prime)\n"
" .collect::<Vec<_>>();\n"
"}\n"
"```"
#: src/traits/from-iterator.md:17
msgid ""
"`Iterator` implements `fn collect<B>(self) -> B where B: FromIterator<Self::"
"Item>, Self: Sized`"
msgstr ""
"`Iterator`에는 다음 함수가 정의되어 있습니다: `fn collect<B>(self) -> B "
"where B: FromIterator<Self::Item>, Self: Sized`"
#: src/traits/from-iterator.md:23
msgid ""
"There are also implementations which let you do cool things like convert an "
"`Iterator<Item = Result<V, E>>` into a `Result<Vec<V>, E>`."
msgstr ""
"`Iterator<Item = Result<V, E>>`을 `Result<Vec<V>, E>`로 변환할 수 있는 멋진 "
"기능들도 구현되어 있습니다."
#: src/traits/from-into.md:1
msgid "`From` and `Into`"
msgstr "`From`과 `Into`"
#: src/traits/from-into.md:3
msgid ""
"Types implement [`From`](https://doc.rust-lang.org/std/convert/trait.From."
"html) and [`Into`](https://doc.rust-lang.org/std/convert/trait.Into.html) to "
"facilitate type conversions:"
msgstr ""
"타입은 용이한 형변환을 위해 [`From`](https://doc.rust-lang.org/std/convert/"
"trait.From.html)과 [`Into`](https://doc.rust-lang.org/std/convert/trait.Into."
"html)를 구현합니다:"
#: src/traits/from-into.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let s = String::from(\"hello\");\n"
" let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);\n"
" let one = i16::from(true);\n"
" let bigger = i32::from(123i16);\n"
" println!(\"{s}, {addr}, {one}, {bigger}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let s = String::from(\"hello\");\n"
" let addr = std::net::Ipv4Addr::from([127, 0, 0, 1]);\n"
" let one = i16::from(true);\n"
" let bigger = i32::from(123i16);\n"
" println!(\"{s}, {addr}, {one}, {bigger}\");\n"
"}\n"
"```"
#: src/traits/from-into.md:15
msgid ""
"[`Into`](https://doc.rust-lang.org/std/convert/trait.Into.html) is "
"automatically implemented when [`From`](https://doc.rust-lang.org/std/"
"convert/trait.From.html) is implemented:"
msgstr ""
"[`From`](https://doc.rust-lang.org/std/convert/trait.From.html)이 구현되면 "
"[`Into`](https://doc.rust-lang.org/std/convert/trait.Into.html) 역시 자동으"
"로 구현됩니다:"
#: src/traits/from-into.md:17
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let s: String = \"hello\".into();\n"
" let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();\n"
" let one: i16 = true.into();\n"
" let bigger: i32 = 123i16.into();\n"
" println!(\"{s}, {addr}, {one}, {bigger}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let s: String = \"hello\".into();\n"
" let addr: std::net::Ipv4Addr = [127, 0, 0, 1].into();\n"
" let one: i16 = true.into();\n"
" let bigger: i32 = 123i16.into();\n"
" println!(\"{s}, {addr}, {one}, {bigger}\");\n"
"}\n"
"```"
#: src/traits/from-into.md:29
msgid ""
"That's why it is common to only implement `From`, as your type will get "
"`Into` implementation too."
msgstr ""
"그렇기 때문에 사용자 정의 타입의 경우에도 `From` 만 구현하는 것이 일반적입니"
"다."
#: src/traits/from-into.md:30
msgid ""
"When declaring a function argument input type like \"anything that can be "
"converted into a `String`\", the rule is opposite, you should use `Into`. "
"Your function will accept types that implement `From` and those that _only_ "
"implement `Into`."
msgstr ""
"\"`String`으로 변환할 수 있는 모든 것\"과 같은 함수의 인수 타입을 선언할 때에"
"는 `Into`를 사용해야 함을 조심하세요. 그래야만, 함수는 `From`을 구현한 타입"
"과 `Into` _만_ 구현한 타입 모두를 인자로 받을 수 있습니다."
#: src/traits/read-write.md:1
msgid "`Read` and `Write`"
msgstr "`Read`와 `Write`"
#: src/traits/read-write.md:3
msgid ""
"Using [`Read`](https://doc.rust-lang.org/std/io/trait.Read.html) and "
"[`BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html), you can "
"abstract over `u8` sources:"
msgstr ""
"[`Read`](https://doc.rust-lang.org/std/io/trait.Read.html)와 [`BufRead`]"
"(https://doc.rust-lang.org/std/io/trait.BufRead.html)를 사용하면 `u8` 타입의 "
"데이터 스트림을 읽을 수 있습니다:"
#: src/traits/read-write.md:5
msgid ""
"```rust,editable\n"
"use std::io::{BufRead, BufReader, Read, Result};\n"
"\n"
"fn count_lines<R: Read>(reader: R) -> usize {\n"
" let buf_reader = BufReader::new(reader);\n"
" buf_reader.lines().count()\n"
"}\n"
"\n"
"fn main() -> Result<()> {\n"
" let slice: &[u8] = b\"foo\\nbar\\nbaz\\n\";\n"
" println!(\"lines in slice: {}\", count_lines(slice));\n"
"\n"
" let file = std::fs::File::open(std::env::current_exe()?)?;\n"
" println!(\"lines in file: {}\", count_lines(file));\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::io::{BufRead, BufReader, Read, Result};\n"
"\n"
"fn count_lines<R: Read>(reader: R) -> usize {\n"
" let buf_reader = BufReader::new(reader);\n"
" buf_reader.lines().count()\n"
"}\n"
"\n"
"fn main() -> Result<()> {\n"
" let slice: &[u8] = b\"foo\\nbar\\nbaz\\n\";\n"
" println!(\"lines in slice: {}\", count_lines(slice));\n"
"\n"
" let file = std::fs::File::open(std::env::current_exe()?)?;\n"
" println!(\"lines in file: {}\", count_lines(file));\n"
" Ok(())\n"
"}\n"
"```"
#: src/traits/read-write.md:23
msgid ""
"Similarly, [`Write`](https://doc.rust-lang.org/std/io/trait.Write.html) lets "
"you abstract over `u8` sinks:"
msgstr "이와 비슷하게, `Write`를 사옹하면 `u8` 타입의 데이터를 쓸 수 있습니다:"
#: src/traits/read-write.md:25
msgid ""
"```rust,editable\n"
"use std::io::{Result, Write};\n"
"\n"
"fn log<W: Write>(writer: &mut W, msg: &str) -> Result<()> {\n"
" writer.write_all(msg.as_bytes())?;\n"
" writer.write_all(\"\\n\".as_bytes())\n"
"}\n"
"\n"
"fn main() -> Result<()> {\n"
" let mut buffer = Vec::new();\n"
" log(&mut buffer, \"Hello\")?;\n"
" log(&mut buffer, \"World\")?;\n"
" println!(\"Logged: {:?}\", buffer);\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::io::{Result, Write};\n"
"\n"
"fn log<W: Write>(writer: &mut W, msg: &str) -> Result<()> {\n"
" writer.write_all(msg.as_bytes())?;\n"
" writer.write_all(\"\\n\".as_bytes())\n"
"}\n"
"\n"
"fn main() -> Result<()> {\n"
" let mut buffer = Vec::new();\n"
" log(&mut buffer, \"Hello\")?;\n"
" log(&mut buffer, \"World\")?;\n"
" println!(\"Logged: {:?}\", buffer);\n"
" Ok(())\n"
"}\n"
"```"
#: src/traits/drop.md:1
msgid "The `Drop` Trait"
msgstr "`Drop` 트레잇"
#: src/traits/drop.md:3
msgid ""
"Values which implement [`Drop`](https://doc.rust-lang.org/std/ops/trait.Drop."
"html) can specify code to run when they go out of scope:"
msgstr ""
"[`Drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html)트레잇을 구현하"
"면, 그 값이 스코프 밖으로 나갈 때 실행될 코드를 작성할 수 있습니다:"
#: src/traits/drop.md:5
msgid ""
"```rust,editable\n"
"struct Droppable {\n"
" name: &'static str,\n"
"}\n"
"\n"
"impl Drop for Droppable {\n"
" fn drop(&mut self) {\n"
" println!(\"Dropping {}\", self.name);\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let a = Droppable { name: \"a\" };\n"
" {\n"
" let b = Droppable { name: \"b\" };\n"
" {\n"
" let c = Droppable { name: \"c\" };\n"
" let d = Droppable { name: \"d\" };\n"
" println!(\"Exiting block B\");\n"
" }\n"
" println!(\"Exiting block A\");\n"
" }\n"
" drop(a);\n"
" println!(\"Exiting main\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"struct Droppable {\n"
" name: &'static str,\n"
"}\n"
"\n"
"impl Drop for Droppable {\n"
" fn drop(&mut self) {\n"
" println!(\"Dropping {}\", self.name);\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let a = Droppable { name: \"a\" };\n"
" {\n"
" let b = Droppable { name: \"b\" };\n"
" {\n"
" let c = Droppable { name: \"c\" };\n"
" let d = Droppable { name: \"d\" };\n"
" println!(\"Exiting block B\");\n"
" }\n"
" println!(\"Exiting block A\");\n"
" }\n"
" drop(a);\n"
" println!(\"Exiting main\");\n"
"}\n"
"```"
#: src/traits/drop.md:34 src/traits/operators.md:26
msgid "Discussion points:"
msgstr "논의점:"
#: src/traits/drop.md:36
msgid "Why doesn't `Drop::drop` take `self`?"
msgstr "`Drop::drop`은 왜 `self`를 인자로 받지 않습니까?"
#: src/traits/drop.md:37
msgid ""
"Short-answer: If it did, `std::mem::drop` would be called at the end of the "
"block, resulting in another call to `Drop::drop`, and a stack overflow!"
msgstr ""
"짧은 대답: 만약 그렇게 된다면 `std::mem::drop`이 블록의 끝에서 호출되고, 다"
"시 `Drop::drop`을 호출하게 되어, 스택 오버플로가 발생합니다!"
#: src/traits/drop.md:40
msgid "Try replacing `drop(a)` with `a.drop()`."
msgstr "`drop(a)`를 `a.drop()`로 변경해 보시기 바랍니다."
#: src/traits/default.md:1
msgid "The `Default` Trait"
msgstr "`Default` 트레잇"
#: src/traits/default.md:3
msgid ""
"[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) trait "
"produces a default value for a type."
msgstr ""
"[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) 트레잇"
"은 어떤 타입에 대한 기본값을 제공합니다."
#: src/traits/default.md:5
msgid ""
"```rust,editable\n"
"#[derive(Debug, Default)]\n"
"struct Derived {\n"
" x: u32,\n"
" y: String,\n"
" z: Implemented,\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"struct Implemented(String);\n"
"\n"
"impl Default for Implemented {\n"
" fn default() -> Self {\n"
" Self(\"John Smith\".into())\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let default_struct = Derived::default();\n"
" println!(\"{default_struct:#?}\");\n"
"\n"
" let almost_default_struct = Derived {\n"
" y: \"Y is set!\".into(),\n"
" ..Derived::default()\n"
" };\n"
" println!(\"{almost_default_struct:#?}\");\n"
"\n"
" let nothing: Option<Derived> = None;\n"
" println!(\"{:#?}\", nothing.unwrap_or_default());\n"
"}\n"
"\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug, Default)]\n"
"struct Derived {\n"
" x: u32,\n"
" y: String,\n"
" z: Implemented,\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"struct Implemented(String);\n"
"\n"
"impl Default for Implemented {\n"
" fn default() -> Self {\n"
" Self(\"John Smith\".into())\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let default_struct = Derived::default();\n"
" println!(\"{default_struct:#?}\");\n"
"\n"
" let almost_default_struct = Derived {\n"
" y: \"Y is set!\".into(),\n"
" ..Derived::default()\n"
" };\n"
" println!(\"{almost_default_struct:#?}\");\n"
"\n"
" let nothing: Option<Derived> = None;\n"
" println!(\"{:#?}\", nothing.unwrap_or_default());\n"
"}\n"
"\n"
"```"
#: src/traits/default.md:40
msgid ""
"It can be implemented directly or it can be derived via `#[derive(Default)]`."
msgstr ""
"트레잇을 직접 구현하거나 `#[derive(Default)]`를 붙여서 컴파일러에게 구현을 맡"
"길 수 있습니다."
#: src/traits/default.md:41
msgid ""
"A derived implementation will produce a value where all fields are set to "
"their default values."
msgstr ""
"컴파일러가 제공하는 자동 구현의 경우 모든 필드에 대해 기본 값을 설정한 새 인"
"스턴스를 반환합니다."
#: src/traits/default.md:42
msgid "This means all types in the struct must implement `Default` too."
msgstr ""
"이는 구조체의 각 필드 타입들이 모두 `Default` 트레잇을 구현해야 함을 의미합니"
"다."
#: src/traits/default.md:43
msgid ""
"Standard Rust types often implement `Default` with reasonable values (e.g. "
"`0`, `\"\"`, etc)."
msgstr ""
"러스트 표준 타입들은 대부분 `Default`를 구현하고 있으며, 기본 값은 `0`이나 "
"`\"\"`처럼 예상 가능한 값들입니다."
#: src/traits/default.md:44
msgid "The partial struct copy works nicely with default."
msgstr ""
"구조체의 일부분만 복사하고 싶을 때 `default`를 편리하게 사용할 수 있습니다."
#: src/traits/default.md:45
msgid ""
"Rust standard library is aware that types can implement `Default` and "
"provides convenience methods that use it."
msgstr ""
"러스트 표준 라이브러리는 `Default` 트레잇을 구현한 타입을 위한 편의 메서드를 "
"제공하기도 합니다."
#: src/traits/default.md:46
msgid ""
"the `..` syntax is called [struct update syntax](https://doc.rust-lang.org/"
"book/ch05-01-defining-structs.html#creating-instances-from-other-instances-"
"with-struct-update-syntax)"
msgstr ""
"이 `..` 문법은 [구조체 업데이트 문법(struct update syntax)](https://doc.rust-"
"lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-"
"instances-with-struct-update-syntax)라고 합니다"
#: src/traits/operators.md:1
msgid "`Add`, `Mul`, ..."
msgstr "`Add`, `Mul`, ..."
#: src/traits/operators.md:3
msgid ""
"Operator overloading is implemented via traits in [`std::ops`](https://doc."
"rust-lang.org/std/ops/index.html):"
msgstr "연산자 오버로드는 `std::ops`에 있는 다양한 트레잇들을 통해 구현됩니다:"
#: src/traits/operators.md:5
msgid ""
"```rust,editable\n"
"#[derive(Debug, Copy, Clone)]\n"
"struct Point { x: i32, y: i32 }\n"
"\n"
"impl std::ops::Add for Point {\n"
" type Output = Self;\n"
"\n"
" fn add(self, other: Self) -> Self {\n"
" Self {x: self.x + other.x, y: self.y + other.y}\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let p1 = Point { x: 10, y: 20 };\n"
" let p2 = Point { x: 100, y: 200 };\n"
" println!(\"{:?} + {:?} = {:?}\", p1, p2, p1 + p2);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[derive(Debug, Copy, Clone)]\n"
"struct Point { x: i32, y: i32 }\n"
"\n"
"impl std::ops::Add for Point {\n"
" type Output = Self;\n"
"\n"
" fn add(self, other: Self) -> Self {\n"
" Self {x: self.x + other.x, y: self.y + other.y}\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let p1 = Point { x: 10, y: 20 };\n"
" let p2 = Point { x: 100, y: 200 };\n"
" println!(\"{:?} + {:?} = {:?}\", p1, p2, p1 + p2);\n"
"}\n"
"```"
#: src/traits/operators.md:28
msgid ""
"You could implement `Add` for `&Point`. In which situations is that useful? "
msgstr ""
"`&Point`가 `Add`를 구현하도록 할 수도 있습니다. 이게 어떤 경우에 유용할까요? "
#: src/traits/operators.md:29
msgid ""
"Answer: `Add:add` consumes `self`. If type `T` for which you are overloading "
"the operator is not `Copy`, you should consider overloading the operator for "
"`&T` as well. This avoids unnecessary cloning on the call site."
msgstr ""
"답: `Add:add`는 `self`를 소모합니다. 만약 타입 `T`가 `Copy`트레잇을 구현하고 "
"있지 않다면 `&T`에 대해서도 연산자 오버로딩을 고려해야 합니다. 이렇게 하면 호"
"출부에서 불필요한 복사를 피할 수 있습니다."
#: src/traits/operators.md:33
msgid ""
"Why is `Output` an associated type? Could it be made a type parameter of the "
"method?"
msgstr "왜 `Output`이 연관된 타입인가요? 타입 파라메터로 만들 수 있을까요?"
#: src/traits/operators.md:34
msgid ""
"Short answer: Function type parameters are controlled by the caller, but "
"associated types (like `Output`) are controlled by the implementor of a "
"trait."
msgstr ""
"답: 타입 파라메터를 호출하는 쪽에서 결정합니다. 반면 연관된 타입(`Output`같"
"은) 은 트레잇을 구현하는 쪽에서 제어 가능합니다."
#: src/traits/operators.md:37
msgid ""
"You could implement `Add` for two different types, e.g. `impl Add<(i32, "
"i32)> for Point` would add a tuple to a `Point`."
msgstr ""
"`Add`를 이용해서 서로 다른 두 개의 타입을 더할 수도 있습니다. 예를 들어 "
"`impl Add<(i32, i32)> for Point`는 튜플을 `Point`에 더할 수 있게 해 줍니다."
#: src/traits/closures.md:1
msgid "Closures"
msgstr "클로저(Closure)"
#: src/traits/closures.md:3
msgid ""
"Closures or lambda expressions have types which cannot be named. However, "
"they implement special [`Fn`](https://doc.rust-lang.org/std/ops/trait.Fn."
"html), [`FnMut`](https://doc.rust-lang.org/std/ops/trait.FnMut.html), and "
"[`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) traits:"
msgstr ""
"클로저 혹은 람다표현식은 익명타입입니다. 이들은 [`Fn`](https://doc.rust-lang."
"org/std/ops/trait.Fn.html),[`FnMut`](https://doc.rust-lang.org/std/ops/trait."
"FnMut.html), [`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) "
"라는 특별한 트레잇을 구현합니다:"
#: src/traits/closures.md:8
msgid ""
"```rust,editable\n"
"fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {\n"
" println!(\"Calling function on {input}\");\n"
" func(input)\n"
"}\n"
"\n"
"fn main() {\n"
" let add_3 = |x| x + 3;\n"
" println!(\"add_3: {}\", apply_with_log(add_3, 10));\n"
" println!(\"add_3: {}\", apply_with_log(add_3, 20));\n"
"\n"
" let mut v = Vec::new();\n"
" let mut accumulate = |x: i32| {\n"
" v.push(x);\n"
" v.iter().sum::<i32>()\n"
" };\n"
" println!(\"accumulate: {}\", apply_with_log(&mut accumulate, 4));\n"
" println!(\"accumulate: {}\", apply_with_log(&mut accumulate, 5));\n"
"\n"
" let multiply_sum = |x| x * v.into_iter().sum::<i32>();\n"
" println!(\"multiply_sum: {}\", apply_with_log(multiply_sum, 3));\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn apply_with_log(func: impl FnOnce(i32) -> i32, input: i32) -> i32 {\n"
" println!(\"Calling function on {input}\");\n"
" func(input)\n"
"}\n"
"\n"
"fn main() {\n"
" let add_3 = |x| x + 3;\n"
" println!(\"add_3: {}\", apply_with_log(add_3, 10));\n"
" println!(\"add_3: {}\", apply_with_log(add_3, 20));\n"
"\n"
" let mut v = Vec::new();\n"
" let mut accumulate = |x: i32| {\n"
" v.push(x);\n"
" v.iter().sum::<i32>()\n"
" };\n"
" println!(\"accumulate: {}\", apply_with_log(&mut accumulate, 4));\n"
" println!(\"accumulate: {}\", apply_with_log(&mut accumulate, 5));\n"
"\n"
" let multiply_sum = |x| x * v.into_iter().sum::<i32>();\n"
" println!(\"multiply_sum: {}\", apply_with_log(multiply_sum, 3));\n"
"}\n"
"```"
#: src/traits/closures.md:34
msgid ""
"An `Fn` (e.g. `add_3`) neither consumes nor mutates captured values, or "
"perhaps captures nothing at all. It can be called multiple times "
"concurrently."
msgstr ""
"`Fn`(예를 들어 `add_3`)은 캡처된 값을 소모도 변경도 하지 않고, 혹은 어떤 것"
"도 캡쳐하지 않았을 수도 있기 때문에 동시에 여러번 호출할 수 있습니다."
#: src/traits/closures.md:37
msgid ""
"An `FnMut` (e.g. `accumulate`) might mutate captured values. You can call it "
"multiple times, but not concurrently."
msgstr ""
"`FnMut`(예를 들어 `accumulate`)는 캡처된 값을 변경할 수 있으므로 여러 번 호출"
"은 가능하지만 동시에 호출 할 수는 없습니다."
#: src/traits/closures.md:40
msgid ""
"If you have an `FnOnce` (e.g. `multiply_sum`), you may only call it once. It "
"might consume captured values."
msgstr ""
"`FnOnce` (예를 들어 `multiply_sum`)는 한번만 호출되며 캡처된 값을 소모합니다."
#: src/traits/closures.md:43
msgid ""
"`FnMut` is a subtype of `FnOnce`. `Fn` is a subtype of `FnMut` and `FnOnce`. "
"I.e. you can use an `FnMut` wherever an `FnOnce` is called for, and you can "
"use an `Fn` wherever an `FnMut` or `FnOnce` is called for."
msgstr ""
"`FnMut` 는 `FnOnce`의 하위타입입니다. `Fn`은 `FnMut`과 `FnOnce`의 하위 타입입"
"니다. 즉, `FnMut`는 `FnOnce`가 호출되는 곳이면 어디서나 사용 할 수 있고 `Fn`"
"은 `FnMut`와 `FnOnce`가 호출되는 곳이면 어디든 사용할 수 있습니다."
#: src/traits/closures.md:47
msgid ""
"The compiler also infers `Copy` (e.g. for `add_3`) and `Clone` (e.g. "
"`multiply_sum`), depending on what the closure captures."
msgstr ""
"컴파일러는 클로저가 무엇을 캡쳐하는지에 따라 `Copy`(예를 들어 `add_3`)과 "
"`Clone`(예를 들어 `multiply_sum`)을 알아서 추론합니다."
#: src/traits/closures.md:50
msgid ""
"By default, closures will capture by reference if they can. The `move` "
"keyword makes them capture by value."
msgstr ""
"기본적으로 클로져는, 가능하다면, 참조를 사용하여 캡쳐를 합니다. `move` 키워드"
"를 쓰면 값으로 캡쳐가 됩니다."
#: src/traits/closures.md:52
msgid ""
"```rust,editable\n"
"fn make_greeter(prefix: String) -> impl Fn(&str) {\n"
" return move |name| println!(\"{} {}\", prefix, name)\n"
"}\n"
"\n"
"fn main() {\n"
" let hi = make_greeter(\"Hi\".to_string());\n"
" hi(\"there\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn make_greeter(prefix: String) -> impl Fn(&str) {\n"
" return move |name| println!(\"{} {}\", prefix, name)\n"
"}\n"
"\n"
"fn main() {\n"
" let hi = make_greeter(\"Hi\".to_string());\n"
" hi(\"there\");\n"
"}\n"
"```"
#: src/exercises/day-3/morning.md:1
msgid "Day 3: Morning Exercises"
msgstr "3일차 오전 연습문제"
#: src/exercises/day-3/morning.md:3
msgid "We will design a classical GUI library traits and trait objects."
msgstr ""
"이번 연습문제에서는 트레잇와 트레잇 객체를 통해 고전적인 GUI 라이브러리를 설"
"계할 것입니다."
#: src/exercises/day-3/simple-gui.md:3
msgid ""
"Let us design a classical GUI library using our new knowledge of traits and "
"trait objects."
msgstr ""
"이번 연습문제에서는 트레잇와 트레잇 객체에 대해 배운것을 활용하여 고전적인 "
"GUI 라이브러리를 설계할 것입니다."
#: src/exercises/day-3/simple-gui.md:6
msgid "We will have a number of widgets in our library:"
msgstr "라이브러리에는 몇 가지 위젯이 있습니다:"
#: src/exercises/day-3/simple-gui.md:8
msgid "`Window`: has a `title` and contains other widgets."
msgstr ""
"`Window`: `title` 속성을 가지고 있으며, 다른 위젯들을 포함할 수 있습니다."
#: src/exercises/day-3/simple-gui.md:9
msgid ""
"`Button`: has a `label` and a callback function which is invoked when the "
"button is pressed."
msgstr ""
"`Button`: `label` 속성을 가지고 있으며, 버튼이 눌렸을때 실행되는 콜백 함수가 "
"있습니다."
#: src/exercises/day-3/simple-gui.md:11
msgid "`Label`: has a `label`."
msgstr "`Label`: `label` 속성을 가지고 있습니다."
#: src/exercises/day-3/simple-gui.md:13
msgid "The widgets will implement a `Widget` trait, see below."
msgstr "위젯들은 모두 `Widget` 트레잇을 구현합니다. 아래 코드를 참조하세요."
#: src/exercises/day-3/simple-gui.md:15
msgid ""
"Copy the code below to <https://play.rust-lang.org/>, fill in the missing "
"`draw_into` methods so that you implement the `Widget` trait:"
msgstr ""
"아래 코드를 <https://play.rust-lang.org/>에 복사하고 누락된 `draw_into`메서드"
"를 채워 넣어 `Widget` 트레잇을 완성해봅시다:"
#: src/exercises/day-3/simple-gui.md:18
msgid ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_imports, unused_variables, dead_code)]\n"
"\n"
"pub trait Widget {\n"
" /// Natural width of `self`.\n"
" fn width(&self) -> usize;\n"
"\n"
" /// Draw the widget into a buffer.\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write);\n"
"\n"
" /// Draw the widget on standard output.\n"
" fn draw(&self) {\n"
" let mut buffer = String::new();\n"
" self.draw_into(&mut buffer);\n"
" println!(\"{buffer}\");\n"
" }\n"
"}\n"
"\n"
"pub struct Label {\n"
" label: String,\n"
"}\n"
"\n"
"impl Label {\n"
" fn new(label: &str) -> Label {\n"
" Label {\n"
" label: label.to_owned(),\n"
" }\n"
" }\n"
"}\n"
"\n"
"pub struct Button {\n"
" label: Label,\n"
" callback: Box<dyn FnMut()>,\n"
"}\n"
"\n"
"impl Button {\n"
" fn new(label: &str, callback: Box<dyn FnMut()>) -> Button {\n"
" Button {\n"
" label: Label::new(label),\n"
" callback,\n"
" }\n"
" }\n"
"}\n"
"\n"
"pub struct Window {\n"
" title: String,\n"
" widgets: Vec<Box<dyn Widget>>,\n"
"}\n"
"\n"
"impl Window {\n"
" fn new(title: &str) -> Window {\n"
" Window {\n"
" title: title.to_owned(),\n"
" widgets: Vec::new(),\n"
" }\n"
" }\n"
"\n"
" fn add_widget(&mut self, widget: Box<dyn Widget>) {\n"
" self.widgets.push(widget);\n"
" }\n"
"\n"
" fn inner_width(&self) -> usize {\n"
" std::cmp::max(\n"
" self.title.chars().count(),\n"
" self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),\n"
" )\n"
" }\n"
"}\n"
"\n"
"\n"
"impl Widget for Label {\n"
" fn width(&self) -> usize {\n"
" unimplemented!()\n"
" }\n"
"\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Widget for Button {\n"
" fn width(&self) -> usize {\n"
" unimplemented!()\n"
" }\n"
"\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Widget for Window {\n"
" fn width(&self) -> usize {\n"
" unimplemented!()\n"
" }\n"
"\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let mut window = Window::new(\"Rust GUI Demo 1.23\");\n"
" window.add_widget(Box::new(Label::new(\"This is a small text GUI demo."
"\")));\n"
" window.add_widget(Box::new(Button::new(\n"
" \"Click me!\",\n"
" Box::new(|| println!(\"You clicked the button!\")),\n"
" )));\n"
" window.draw();\n"
"}\n"
"```"
msgstr ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_imports, unused_variables, dead_code)]\n"
"\n"
"pub trait Widget {\n"
" /// Natural width of `self`.\n"
" fn width(&self) -> usize;\n"
"\n"
" /// Draw the widget into a buffer.\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write);\n"
"\n"
" /// Draw the widget on standard output.\n"
" fn draw(&self) {\n"
" let mut buffer = String::new();\n"
" self.draw_into(&mut buffer);\n"
" println!(\"{buffer}\");\n"
" }\n"
"}\n"
"\n"
"pub struct Label {\n"
" label: String,\n"
"}\n"
"\n"
"impl Label {\n"
" fn new(label: &str) -> Label {\n"
" Label {\n"
" label: label.to_owned(),\n"
" }\n"
" }\n"
"}\n"
"\n"
"pub struct Button {\n"
" label: Label,\n"
" callback: Box<dyn FnMut()>,\n"
"}\n"
"\n"
"impl Button {\n"
" fn new(label: &str, callback: Box<dyn FnMut()>) -> Button {\n"
" Button {\n"
" label: Label::new(label),\n"
" callback,\n"
" }\n"
" }\n"
"}\n"
"\n"
"pub struct Window {\n"
" title: String,\n"
" widgets: Vec<Box<dyn Widget>>,\n"
"}\n"
"\n"
"impl Window {\n"
" fn new(title: &str) -> Window {\n"
" Window {\n"
" title: title.to_owned(),\n"
" widgets: Vec::new(),\n"
" }\n"
" }\n"
"\n"
" fn add_widget(&mut self, widget: Box<dyn Widget>) {\n"
" self.widgets.push(widget);\n"
" }\n"
"\n"
" fn inner_width(&self) -> usize {\n"
" std::cmp::max(\n"
" self.title.chars().count(),\n"
" self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),\n"
" )\n"
" }\n"
"}\n"
"\n"
"\n"
"impl Widget for Label {\n"
" fn width(&self) -> usize {\n"
" unimplemented!()\n"
" }\n"
"\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Widget for Button {\n"
" fn width(&self) -> usize {\n"
" unimplemented!()\n"
" }\n"
"\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Widget for Window {\n"
" fn width(&self) -> usize {\n"
" unimplemented!()\n"
" }\n"
"\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" let mut window = Window::new(\"Rust GUI Demo 1.23\");\n"
" window.add_widget(Box::new(Label::new(\"This is a small text GUI demo."
"\")));\n"
" window.add_widget(Box::new(Button::new(\n"
" \"Click me!\",\n"
" Box::new(|| println!(\"You clicked the button!\")),\n"
" )));\n"
" window.draw();\n"
"}\n"
"```"
#: src/exercises/day-3/simple-gui.md:130
msgid "The output of the above program can be something simple like this:"
msgstr "위 프로그램의 출력은 아래와 같습니다:"
#: src/exercises/day-3/simple-gui.md:132
msgid ""
"```text\n"
"========\n"
"Rust GUI Demo 1.23\n"
"========\n"
"\n"
"This is a small text GUI demo.\n"
"\n"
"| Click me! |\n"
"```"
msgstr ""
"```text\n"
"========\n"
"Rust GUI Demo 1.23\n"
"========\n"
"\n"
"This is a small text GUI demo.\n"
"\n"
"| Click me! |\n"
"```"
#: src/exercises/day-3/simple-gui.md:142
msgid ""
"If you want to draw aligned text, you can use the [fill/alignment](https://"
"doc.rust-lang.org/std/fmt/index.html#fillalignment) formatting operators. In "
"particular, notice how you can pad with different characters (here a `'/'`) "
"and how you can control alignment:"
msgstr ""
"텍스트를 줄맞춤 해서 그리려면 [fill/alignment](https://doc.rust-lang.org/std/"
"fmt/index.html#fillalignment)를 참조하시기 바랍니다. 특수 문자(여기서는 "
"`'/'`)로 패딩을 주는 방법과 정렬을 제어하는 방법을 확인하시기 바랍니다:"
#: src/exercises/day-3/simple-gui.md:147
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let width = 10;\n"
" println!(\"left aligned: |{:/<width$}|\", \"foo\");\n"
" println!(\"centered: |{:/^width$}|\", \"foo\");\n"
" println!(\"right aligned: |{:/>width$}|\", \"foo\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let width = 10;\n"
" println!(\"left aligned: |{:/<width$}|\", \"foo\");\n"
" println!(\"centered: |{:/^width$}|\", \"foo\");\n"
" println!(\"right aligned: |{:/>width$}|\", \"foo\");\n"
"}\n"
"```"
#: src/exercises/day-3/simple-gui.md:156
msgid ""
"Using such alignment tricks, you can for example produce output like this:"
msgstr "위의 정렬 트릭을 사용하여 다음과 같은 출력을 생성할 수 있습니다:"
#: src/exercises/day-3/simple-gui.md:158
msgid ""
"```text\n"
"+--------------------------------+\n"
"| Rust GUI Demo 1.23 |\n"
"+================================+\n"
"| This is a small text GUI demo. |\n"
"| +-----------+ |\n"
"| | Click me! | |\n"
"| +-----------+ |\n"
"+--------------------------------+\n"
"```"
msgstr ""
"```text\n"
"+--------------------------------+\n"
"| Rust GUI Demo 1.23 |\n"
"+================================+\n"
"| This is a small text GUI demo. |\n"
"| +-----------+ |\n"
"| | Click me! | |\n"
"| +-----------+ |\n"
"+--------------------------------+\n"
"```"
#: src/error-handling.md:3
msgid "Error handling in Rust is done using explicit control flow:"
msgstr "러스트에서 오류는 명시적인 흐름을 따라 처리가 됩니다:"
#: src/error-handling.md:5
msgid "Functions that can have errors list this in their return type,"
msgstr "오류를 발생할 수 있는 함수는 반환 타입에 이를 명시해야 합니다,"
#: src/error-handling.md:6
msgid "There are no exceptions."
msgstr "예외(exception) 기능은 없습니다."
#: src/error-handling/panics.md:3
msgid "Rust will trigger a panic if a fatal error happens at runtime:"
msgstr "러스트는 수행 중 치명적인 오류를 만나면 패닉을 발생할 것입니다:"
#: src/error-handling/panics.md:5
msgid ""
"```rust,editable,should_panic\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" println!(\"v[100]: {}\", v[100]);\n"
"}\n"
"```"
msgstr ""
"```rust,editable,should_panic\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" println!(\"v[100]: {}\", v[100]);\n"
"}\n"
"```"
#: src/error-handling/panics.md:12
msgid "Panics are for unrecoverable and unexpected errors."
msgstr "패닉은 복구할 수 없고 예상치 못한 오류입니다."
#: src/error-handling/panics.md:13
msgid "Panics are symptoms of bugs in the program."
msgstr "패닉은 프로그램에 버그가 있다는 것을 나타냅니다."
#: src/error-handling/panics.md:14
msgid ""
"Use non-panicking APIs (such as `Vec::get`) if crashing is not acceptable."
msgstr ""
"충돌(크래시)을 허용하지 않아야 하는 경우, 패닉을 유발하지 않는 API(`Vec::get`"
"등)를 사용하면 됩니다."
#: src/error-handling/panic-unwind.md:1
msgid "Catching the Stack Unwinding"
msgstr "스택 되감기"
#: src/error-handling/panic-unwind.md:3
msgid ""
"By default, a panic will cause the stack to unwind. The unwinding can be "
"caught:"
msgstr ""
"기본적으로, 패닉이 발생하면 스택 되감기를 합니다. 스택 되감기는 다음과 같이 "
"캐치가 가능합니다:"
#: src/error-handling/panic-unwind.md:5
msgid ""
"```rust,editable\n"
"use std::panic;\n"
"\n"
"fn main() {\n"
" let result = panic::catch_unwind(|| {\n"
" println!(\"hello!\");\n"
" });\n"
" assert!(result.is_ok());\n"
" \n"
" let result = panic::catch_unwind(|| {\n"
" panic!(\"oh no!\");\n"
" });\n"
" assert!(result.is_err());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::panic;\n"
"\n"
"fn main() {\n"
" let result = panic::catch_unwind(|| {\n"
" println!(\"hello!\");\n"
" });\n"
" assert!(result.is_ok());\n"
" \n"
" let result = panic::catch_unwind(|| {\n"
" panic!(\"oh no!\");\n"
" });\n"
" assert!(result.is_err());\n"
"}\n"
"```"
#: src/error-handling/panic-unwind.md:21
msgid ""
"This can be useful in servers which should keep running even if a single "
"request crashes."
msgstr ""
"이것은 단일 요청이 크래시 되더라도 프로그램이 계속 실행되야 하는 서버에 유용"
"합니다."
#: src/error-handling/panic-unwind.md:23
msgid "This does not work if `panic = 'abort'` is set in your `Cargo.toml`."
msgstr ""
"만약 `Cargo.toml`설정파일에 `panic = abort`을 설정했다면 크래시를 캐치할 수 "
"없습니다."
#: src/error-handling/result.md:1
msgid "Structured Error Handling with `Result`"
msgstr "`Result`를 이용한 구조화된 오류처리"
#: src/error-handling/result.md:3
msgid ""
"We have already seen the `Result` enum. This is used pervasively when errors "
"are expected as part of normal operation:"
msgstr ""
"여러분은 이미 `Result` 열거형을 몇 번 봤습니다. 이 타입은 프로그램의 정상적"
"인 수행 중에 발생할 수 있는 오류값들을 나타내기 위해 사용됩니다:"
#: src/error-handling/result.md:6
msgid ""
"```rust,editable\n"
"use std::fs;\n"
"use std::io::Read;\n"
"\n"
"fn main() {\n"
" let file = fs::File::open(\"diary.txt\");\n"
" match file {\n"
" Ok(mut file) => {\n"
" let mut contents = String::new();\n"
" file.read_to_string(&mut contents);\n"
" println!(\"Dear diary: {contents}\");\n"
" },\n"
" Err(err) => {\n"
" println!(\"The diary could not be opened: {err}\");\n"
" }\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::fs;\n"
"use std::io::Read;\n"
"\n"
"fn main() {\n"
" let file = fs::File::open(\"diary.txt\");\n"
" match file {\n"
" Ok(mut file) => {\n"
" let mut contents = String::new();\n"
" file.read_to_string(&mut contents);\n"
" println!(\"Dear diary: {contents}\");\n"
" },\n"
" Err(err) => {\n"
" println!(\"The diary could not be opened: {err}\");\n"
" }\n"
" }\n"
"}\n"
"```"
#: src/error-handling/result.md:27
msgid ""
"As with `Option`, the successful value sits inside of `Result`, forcing the "
"developer to explicitly extract it. This encourages error checking. In the "
"case where an error should never happen, `unwrap()` or `expect()` can be "
"called, and this is a signal of the developer intent too."
msgstr ""
"`Option`와 마찬가지로, 성공한 경우의 값은 `Result` 내부에 있습니다. 그래서, "
"개발자는 명시적으로 이를 추출하여야 합니다. 이렇게 함으로써 값을 읽기 전에 오"
"류 발생 여부를 반드시 체크하도록 유도하고 있습니다. 만일 오류가 절대 발생하"
"지 않는 경우라면 `unwrap()`이나 `expect()`를 사용할 수 있으며, 이는 개발자의 "
"의도(_역주_: 오류가 발생할 수 없음)을 명시적으로 나타내는 방법이기도 합니다."
#: src/error-handling/result.md:30
msgid ""
"`Result` documentation is a recommended read. Not during the course, but it "
"is worth mentioning. It contains a lot of convenience methods and functions "
"that help functional-style programming. "
msgstr ""
"수업중엔 아니지만 `Result`의 API 레퍼런스를 읽는 것을 권장합니다. 함수형 프로"
"그래밍 스타일에 도움이 되는 편리한 메서드와 함수를 많이 배울 수 있습니다. "
#: src/error-handling/try-operator.md:1
msgid "Propagating Errors with `?`"
msgstr "`?`를 이용한 오류 전파"
#: src/error-handling/try-operator.md:3
msgid ""
"The try-operator `?` is used to return errors to the caller. It lets you "
"turn the common"
msgstr ""
"연산자 `?`는 호출자에게 오류를 반환할 때 사용합니다. 이를 이용하면 이런 코드"
"를"
#: src/error-handling/try-operator.md:6
msgid ""
"```rust,ignore\n"
"match some_expression {\n"
" Ok(value) => value,\n"
" Err(err) => return Err(err),\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"match some_expression {\n"
" Ok(value) => value,\n"
" Err(err) => return Err(err),\n"
"}\n"
"```"
#: src/error-handling/try-operator.md:13
msgid "into the much simpler"
msgstr "이렇게 짧게 쓸 수 있습니다"
#: src/error-handling/try-operator.md:15
msgid ""
"```rust,ignore\n"
"some_expression?\n"
"```"
msgstr ""
"```rust,ignore\n"
"some_expression?\n"
"```"
#: src/error-handling/try-operator.md:19
msgid "We can use this to simplify our error handling code:"
msgstr "이제 우리 예제에 적용해 보겠습니다:"
#: src/error-handling/try-operator.md:21
msgid ""
"```rust,editable\n"
"use std::{fs, io};\n"
"use std::io::Read;\n"
"\n"
"fn read_username(path: &str) -> Result<String, io::Error> {\n"
" let username_file_result = fs::File::open(path);\n"
" let mut username_file = match username_file_result {\n"
" Ok(file) => file,\n"
" Err(err) => return Err(err),\n"
" };\n"
"\n"
" let mut username = String::new();\n"
" match username_file.read_to_string(&mut username) {\n"
" Ok(_) => Ok(username),\n"
" Err(err) => Err(err),\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"alice\").unwrap();\n"
" let username = read_username(\"config.dat\");\n"
" println!(\"username or error: {username:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::{fs, io};\n"
"use std::io::Read;\n"
"\n"
"fn read_username(path: &str) -> Result<String, io::Error> {\n"
" let username_file_result = fs::File::open(path);\n"
" let mut username_file = match username_file_result {\n"
" Ok(file) => file,\n"
" Err(err) => return Err(err),\n"
" };\n"
"\n"
" let mut username = String::new();\n"
" match username_file.read_to_string(&mut username) {\n"
" Ok(_) => Ok(username),\n"
" Err(err) => Err(err),\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"alice\").unwrap();\n"
" let username = read_username(\"config.dat\");\n"
" println!(\"username or error: {username:?}\");\n"
"}\n"
"```"
#: src/error-handling/try-operator.md:50
#: src/error-handling/converting-error-types-example.md:52
msgid "The `username` variable can be either `Ok(string)` or `Err(error)`."
msgstr "`username` 변수는 `Ok(string)`이거나 `Err(error)`일 수 있습니다."
#: src/error-handling/try-operator.md:51
#: src/error-handling/converting-error-types-example.md:53
msgid ""
"Use the `fs::write` call to test out the different scenarios: no file, empty "
"file, file with username."
msgstr ""
"`fs::write` 메서드를 사용하여 파일이 없거나, 비었거나, 중복되는 경우 등을 테"
"스트해 봅니다."
#: src/error-handling/try-operator.md:52
msgid ""
"The return type of the function has to be compatible with the nested "
"functions it calls. For instance, a function returning a `Result<T, Err>` "
"can only apply the `?` operator on a function returning a `Result<AnyT, "
"Err>`. It cannot apply the `?` operator on a function returning an "
"`Option<AnyT>` or `Result<T, OtherErr>` unless `OtherErr` implements "
"`From<Err>`. Reciprocally, a function returning an `Option<T>` can only "
"apply the `?` operator on a function returning an `Option<AnyT>`."
msgstr ""
"함수의 리턴 타입은 네스팅 되어 호출되는 함수의 리턴 타입과 호환되어야 합니"
"다. 예를 들어 `Result<T, Err>`를 리턴하는 함수는 `Result<AnyT, Err>`를 리턴하"
"는 함수를 호출할 때에만`?`를 사용할 수 있습니다. `Option<AnyT>`나 `Result<T, "
"OtherErr>` (`OtherError`가 `From<Err>`를 구현하지 않는 다고 가정할 때)와 같"
"은 타입을 리턴하는 함수를 호출할 때에는 `?`를 사용할 수 없습니다. 동일한 이유"
"로, `Option<T>`를 리턴하는 함수는 `Option<AnyT>`를 리턴하는 함수를 호출할 때"
"에만 `?`를 사용할 수 있습니다."
#: src/error-handling/try-operator.md:57
msgid ""
"You can convert incompatible types into one another with the different "
"`Option` and `Result` methods such as `Option::ok_or`, `Result::ok`, "
"`Result::err`."
msgstr ""
"`Option`과 `Result`간의 변환을 위해 `Option::ok_or`, `Result::ok`, `Result::"
"err`와 같은 함수들을 사용할 수 있습니다."
#: src/error-handling/converting-error-types.md:3
msgid ""
"The effective expansion of `?` is a little more complicated than previously "
"indicated:"
msgstr "실제로 `?`가 적용되는 과정은 아까 설명한 것 보다 좀 더 복잡합니다:"
#: src/error-handling/converting-error-types.md:5
msgid ""
"```rust,ignore\n"
"expression?\n"
"```"
msgstr ""
"```rust,ignore\n"
"expression?\n"
"```"
#: src/error-handling/converting-error-types.md:9
msgid "works the same as"
msgstr "위 표현은 아래와 같습니다"
#: src/error-handling/converting-error-types.md:11
msgid ""
"```rust,ignore\n"
"match expression {\n"
" Ok(value) => value,\n"
" Err(err) => return Err(From::from(err)),\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"match expression {\n"
" Ok(value) => value,\n"
" Err(err) => return Err(From::from(err)),\n"
"}\n"
"```"
#: src/error-handling/converting-error-types.md:18
msgid ""
"The `From::from` call here means we attempt to convert the error type to the "
"type returned by the function:"
msgstr ""
"`From::from`을 통해 원래의 에러 타입을 이 함수가 반환하는 에러 타입으로 변환"
"하고 있습니다:"
#: src/error-handling/converting-error-types-example.md:3
msgid ""
"```rust,editable\n"
"use std::error::Error;\n"
"use std::fmt::{self, Display, Formatter};\n"
"use std::fs::{self, File};\n"
"use std::io::{self, Read};\n"
"\n"
"#[derive(Debug)]\n"
"enum ReadUsernameError {\n"
" IoError(io::Error),\n"
" EmptyUsername(String),\n"
"}\n"
"\n"
"impl Error for ReadUsernameError {}\n"
"\n"
"impl Display for ReadUsernameError {\n"
" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n"
" match self {\n"
" Self::IoError(e) => write!(f, \"IO error: {e}\"),\n"
" Self::EmptyUsername(filename) => write!(f, \"Found no username "
"in {filename}\"),\n"
" }\n"
" }\n"
"}\n"
"\n"
"impl From<io::Error> for ReadUsernameError {\n"
" fn from(err: io::Error) -> ReadUsernameError {\n"
" ReadUsernameError::IoError(err)\n"
" }\n"
"}\n"
"\n"
"fn read_username(path: &str) -> Result<String, ReadUsernameError> {\n"
" let mut username = String::with_capacity(100);\n"
" File::open(path)?.read_to_string(&mut username)?;\n"
" if username.is_empty() {\n"
" return Err(ReadUsernameError::EmptyUsername(String::from(path)));\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" let username = read_username(\"config.dat\");\n"
" println!(\"username or error: {username:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::error::Error;\n"
"use std::fmt::{self, Display, Formatter};\n"
"use std::fs::{self, File};\n"
"use std::io::{self, Read};\n"
"\n"
"#[derive(Debug)]\n"
"enum ReadUsernameError {\n"
" IoError(io::Error),\n"
" EmptyUsername(String),\n"
"}\n"
"\n"
"impl Error for ReadUsernameError {}\n"
"\n"
"impl Display for ReadUsernameError {\n"
" fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n"
" match self {\n"
" Self::IoError(e) => write!(f, \"IO error: {e}\"),\n"
" Self::EmptyUsername(filename) => write!(f, \"Found no username "
"in {filename}\"),\n"
" }\n"
" }\n"
"}\n"
"\n"
"impl From<io::Error> for ReadUsernameError {\n"
" fn from(err: io::Error) -> ReadUsernameError {\n"
" ReadUsernameError::IoError(err)\n"
" }\n"
"}\n"
"\n"
"fn read_username(path: &str) -> Result<String, ReadUsernameError> {\n"
" let mut username = String::with_capacity(100);\n"
" File::open(path)?.read_to_string(&mut username)?;\n"
" if username.is_empty() {\n"
" return Err(ReadUsernameError::EmptyUsername(String::from(path)));\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" let username = read_username(\"config.dat\");\n"
" println!(\"username or error: {username:?}\");\n"
"}\n"
"```"
#: src/error-handling/converting-error-types-example.md:55
msgid ""
"It is good practice for all error types that don't need to be `no_std` to "
"implement `std::error::Error`, which requires `Debug` and `Display`. The "
"`Error` crate for `core` is only available in [nightly](https://github.com/"
"rust-lang/rust/issues/103765), so not fully `no_std` compatible yet."
msgstr ""
"모든 에러 타입 (`no_std`이어야 하는 에러 타입을 제외하고)에 대해 `std::"
"error::Error`를 구현하는 것은 좋은 습관입니다. `std::error::Error`를 구현한다"
"는 것은 `Debug`와 `Display`도 구현한다는 것입니다. `core`를 위한 `Error`크레"
"이크는 [나이틀리](https://github.com/rust-lang/rust/issues/103765)에만 제공"
"이 됩니다. 그래서 아직 `no_std`환경에서 사용할 수는 없습니다."
#: src/error-handling/converting-error-types-example.md:57
msgid ""
"It's generally helpful for them to implement `Clone` and `Eq` too where "
"possible, to make life easier for tests and consumers of your library. In "
"this case we can't easily do so, because `io::Error` doesn't implement them."
msgstr ""
"가능하다면 `Clone`과 `Eq` 트레잇도 구현하도록 하세요. 여러분의 라이브러리가 "
"테스트 하기 쉬워지고, 사용하기 좋아질 겁니다. 다만, 이 예제에서는 그렇게 하"
"기 힘듭니다. 왜냐하면 `io::Error`는 이 트레잇들을 구현하고 있지 않기 때문입니"
"다."
#: src/error-handling/deriving-error-enums.md:3
msgid ""
"The [thiserror](https://docs.rs/thiserror/) crate is a popular way to create "
"an error enum like we did on the previous page:"
msgstr ""
"[thiserror](https://docs.rs/thiserror/)는, 이전 페이지에서 보았던 것과 같은 "
"에러 열거형을 쉽게 만들 수 있게 해 주는 유명한 크레이트 입니다:"
#: src/error-handling/deriving-error-enums.md:6
msgid ""
"```rust,editable,compile_fail\n"
"use std::{fs, io};\n"
"use std::io::Read;\n"
"use thiserror::Error;\n"
"\n"
"#[derive(Debug, Error)]\n"
"enum ReadUsernameError {\n"
" #[error(\"Could not read: {0}\")]\n"
" IoError(#[from] io::Error),\n"
" #[error(\"Found no username in {0}\")]\n"
" EmptyUsername(String),\n"
"}\n"
"\n"
"fn read_username(path: &str) -> Result<String, ReadUsernameError> {\n"
" let mut username = String::new();\n"
" fs::File::open(path)?.read_to_string(&mut username)?;\n"
" if username.is_empty() {\n"
" return Err(ReadUsernameError::EmptyUsername(String::from(path)));\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" match read_username(\"config.dat\") {\n"
" Ok(username) => println!(\"Username: {username}\"),\n"
" Err(err) => println!(\"Error: {err}\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use std::{fs, io};\n"
"use std::io::Read;\n"
"use thiserror::Error;\n"
"\n"
"#[derive(Debug, Error)]\n"
"enum ReadUsernameError {\n"
" #[error(\"Could not read: {0}\")]\n"
" IoError(#[from] io::Error),\n"
" #[error(\"Found no username in {0}\")]\n"
" EmptyUsername(String),\n"
"}\n"
"\n"
"fn read_username(path: &str) -> Result<String, ReadUsernameError> {\n"
" let mut username = String::new();\n"
" fs::File::open(path)?.read_to_string(&mut username)?;\n"
" if username.is_empty() {\n"
" return Err(ReadUsernameError::EmptyUsername(String::from(path)));\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" match read_username(\"config.dat\") {\n"
" Ok(username) => println!(\"Username: {username}\"),\n"
" Err(err) => println!(\"Error: {err}\"),\n"
" }\n"
"}\n"
"```"
#: src/error-handling/deriving-error-enums.md:39
msgid ""
"`thiserror`'s derive macro automatically implements `std::error::Error`, and "
"optionally `Display` (if the `#[error(...)]` attributes are provided) and "
"`From` (if the `#[from]` attribute is added). It also works for structs."
msgstr ""
"`thiserror`의 derive 매크로를 이용하면 `std::error::Error`과 `Display`(만약 "
"`#[error(...)]` 어트리뷰트를 추가했을 경우), `From`(만약 `#[from]` 어트리뷰트"
"를 추가했을 경우) 트레잇들이 자동으로 구현이 됩니다. 구조체에 대해서도 사용 "
"가능합니다."
#: src/error-handling/deriving-error-enums.md:43
msgid "It doesn't affect your public API, which makes it good for libraries."
msgstr ""
"이 매크로를 사용해도 밖으로 노출되는 API가 변경되지는 않습니다. 라이브러리를 "
"만들 경우에는 이게 중요하죠."
#: src/error-handling/dynamic-errors.md:3
msgid ""
"Sometimes we want to allow any type of error to be returned without writing "
"our own enum covering all the different possibilities. `std::error::Error` "
"makes this easy."
msgstr ""
"때때로 우리는, 발생 가능한 모든 에러를 일일히 열거하지 않고, 어떤 종류의 에러"
"라도 상관없이 리턴하고 싶을 때가 있습니다. `std::error::Error`를 이용하면 쉽"
"습니다."
#: src/error-handling/dynamic-errors.md:6
msgid ""
"```rust,editable,compile_fail\n"
"use std::fs;\n"
"use std::io::Read;\n"
"use thiserror::Error;\n"
"use std::error::Error;\n"
"\n"
"#[derive(Clone, Debug, Eq, Error, PartialEq)]\n"
"#[error(\"Found no username in {0}\")]\n"
"struct EmptyUsernameError(String);\n"
"\n"
"fn read_username(path: &str) -> Result<String, Box<dyn Error>> {\n"
" let mut username = String::new();\n"
" fs::File::open(path)?.read_to_string(&mut username)?;\n"
" if username.is_empty() {\n"
" return Err(EmptyUsernameError(String::from(path)).into());\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" match read_username(\"config.dat\") {\n"
" Ok(username) => println!(\"Username: {username}\"),\n"
" Err(err) => println!(\"Error: {err}\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use std::fs;\n"
"use std::io::Read;\n"
"use thiserror::Error;\n"
"use std::error::Error;\n"
"\n"
"#[derive(Clone, Debug, Eq, Error, PartialEq)]\n"
"#[error(\"Found no username in {0}\")]\n"
"struct EmptyUsernameError(String);\n"
"\n"
"fn read_username(path: &str) -> Result<String, Box<dyn Error>> {\n"
" let mut username = String::new();\n"
" fs::File::open(path)?.read_to_string(&mut username)?;\n"
" if username.is_empty() {\n"
" return Err(EmptyUsernameError(String::from(path)).into());\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" match read_username(\"config.dat\") {\n"
" Ok(username) => println!(\"Username: {username}\"),\n"
" Err(err) => println!(\"Error: {err}\"),\n"
" }\n"
"}\n"
"```"
#: src/error-handling/dynamic-errors.md:36
msgid ""
"This saves on code, but gives up the ability to cleanly handle different "
"error cases differently in the program. As such it's generally not a good "
"idea to use `Box<dyn Error>` in the public API of a library, but it can be a "
"good option in a program where you just want to display the error message "
"somewhere."
msgstr ""
"이렇게 하면 코드의 양을 줄일 수 있습니다. 그러나 서로 다른 종류의 에러를 구별"
"하여 다르게 처리하는 것이 불가능해 집니다. 때문에, `Box<dyn Error>`를 라이브"
"러리의 API로 노출하는게 좋은 디자인은 아닙니다. 에러 발생 시, 그저 에러 메시"
"지를 출력하고 싶은 경우와 같이 제한된 상황에서는 유용할 수 있습니다."
#: src/error-handling/error-contexts.md:3
msgid ""
"The widely used [anyhow](https://docs.rs/anyhow/) crate can help you add "
"contextual information to your errors and allows you to have fewer custom "
"error types:"
msgstr ""
"[anyhow](https://docs.rs/anyhow/) 크레이트는 에러에 에러가 발생한 문맥에 대"
"한 정보를 추가하기 위해 널리 사용되며, 이를 이용하면 서로 다른 문맥을 나타내"
"기 사용자 정의 오류 타입을 많이 만들어야 하는 불편함을 피할 수 있습니다:"
#: src/error-handling/error-contexts.md:7
msgid ""
"```rust,editable,compile_fail\n"
"use std::{fs, io};\n"
"use std::io::Read;\n"
"use anyhow::{Context, Result, bail};\n"
"\n"
"fn read_username(path: &str) -> Result<String> {\n"
" let mut username = String::with_capacity(100);\n"
" fs::File::open(path)\n"
" .with_context(|| format!(\"Failed to open {path}\"))?\n"
" .read_to_string(&mut username)\n"
" .context(\"Failed to read\")?;\n"
" if username.is_empty() {\n"
" bail!(\"Found no username in {path}\");\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" match read_username(\"config.dat\") {\n"
" Ok(username) => println!(\"Username: {username}\"),\n"
" Err(err) => println!(\"Error: {err:?}\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use std::{fs, io};\n"
"use std::io::Read;\n"
"use anyhow::{Context, Result, bail};\n"
"\n"
"fn read_username(path: &str) -> Result<String> {\n"
" let mut username = String::with_capacity(100);\n"
" fs::File::open(path)\n"
" .with_context(|| format!(\"Failed to open {path}\"))?\n"
" .read_to_string(&mut username)\n"
" .context(\"Failed to read\")?;\n"
" if username.is_empty() {\n"
" bail!(\"Found no username in {path}\");\n"
" }\n"
" Ok(username)\n"
"}\n"
"\n"
"fn main() {\n"
" //fs::write(\"config.dat\", \"\").unwrap();\n"
" match read_username(\"config.dat\") {\n"
" Ok(username) => println!(\"Username: {username}\"),\n"
" Err(err) => println!(\"Error: {err:?}\"),\n"
" }\n"
"}\n"
"```"
#: src/error-handling/error-contexts.md:35
msgid "`anyhow::Result<V>` is a type alias for `Result<V, anyhow::Error>`."
msgstr ""
"`anyhow::Result<V>`는 `Result<V, anyhow::Error>`의 타입 앨리어스(alias)입니"
"다."
#: src/error-handling/error-contexts.md:36
msgid ""
"`anyhow::Error` is essentially a wrapper around `Box<dyn Error>`. As such "
"it's again generally not a good choice for the public API of a library, but "
"is widely used in applications."
msgstr ""
"`anyhow::Error`는 `Box<dyn Error>`의 래퍼 타입이라 할 수 있습니다. 따라서 라"
"이브러리의 공개 API로서 사용하기에 부적합하다고 할 수 있지만 많은 애플리케이"
"션에 널리 사용되고 있습니다."
#: src/error-handling/error-contexts.md:38
msgid ""
"Actual error type inside of it can be extracted for examination if necessary."
msgstr ""
"필요하다면 `anyhow::Error`에 저장된 진짜 에러 타입을 꺼내어 검사할 수도 있습"
"니다."
#: src/error-handling/error-contexts.md:39
msgid ""
"Functionality provided by `anyhow::Result<T>` may be familiar to Go "
"developers, as it provides similar usage patterns and ergonomics to `(T, "
"error)` from Go."
msgstr ""
"`anyhow::Result<T>`가 제공하는 기능들이 Go 언어 개발자들에게는 익숙할 것입니"
"다. Go언어에서 반환 값으로 사용하는 `(T, error)` 패턴과 비슷하기 때문입니다."
#: src/testing.md:3
msgid "Rust and Cargo come with a simple unit test framework:"
msgstr ""
"러스트와 카고(cargo)는 간단한 단위 테스트 프레임워크와 함께 제공됩니다:"
#: src/testing.md:5
msgid "Unit tests are supported throughout your code."
msgstr "단위 테스트는 코드 전반에서 지원됩니다."
#: src/testing.md:7
msgid "Integration tests are supported via the `tests/` directory."
msgstr "통합 테스트는 `tests/` 디렉터리를 통해 지원됩니다."
#: src/testing/unit-tests.md:3
msgid "Mark unit tests with `#[test]`:"
msgstr "단위 테스트는 `#[test]` 로 표시합니다:"
#: src/testing/unit-tests.md:5
msgid ""
"```rust,editable,ignore\n"
"fn first_word(text: &str) -> &str {\n"
" match text.find(' ') {\n"
" Some(idx) => &text[..idx],\n"
" None => &text,\n"
" }\n"
"}\n"
"\n"
"#[test]\n"
"fn test_empty() {\n"
" assert_eq!(first_word(\"\"), \"\");\n"
"}\n"
"\n"
"#[test]\n"
"fn test_single_word() {\n"
" assert_eq!(first_word(\"Hello\"), \"Hello\");\n"
"}\n"
"\n"
"#[test]\n"
"fn test_multiple_words() {\n"
" assert_eq!(first_word(\"Hello World\"), \"Hello\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,ignore\n"
"fn first_word(text: &str) -> &str {\n"
" match text.find(' ') {\n"
" Some(idx) => &text[..idx],\n"
" None => &text,\n"
" }\n"
"}\n"
"\n"
"#[test]\n"
"fn test_empty() {\n"
" assert_eq!(first_word(\"\"), \"\");\n"
"}\n"
"\n"
"#[test]\n"
"fn test_single_word() {\n"
" assert_eq!(first_word(\"Hello\"), \"Hello\");\n"
"}\n"
"\n"
"#[test]\n"
"fn test_multiple_words() {\n"
" assert_eq!(first_word(\"Hello World\"), \"Hello\");\n"
"}\n"
"```"
#: src/testing/unit-tests.md:29
msgid "Use `cargo test` to find and run the unit tests."
msgstr "`cargo test` 커맨드를 사용하면 단위 테스트를 찾아서 실행합니다."
#: src/testing/test-modules.md:3
msgid ""
"Unit tests are often put in a nested module (run tests on the [Playground]"
"(https://play.rust-lang.org/)):"
msgstr ""
"단위 테스트는 원래 모듈 밑에 서브 모듈로 만드는 경우가 많습니다. ([플레이그라"
"운드](https://play.rust-lang.org/)에서 다음 테스트를 수행해 보세요):"
#: src/testing/test-modules.md:6
msgid ""
"```rust,editable\n"
"fn helper(a: &str, b: &str) -> String {\n"
" format!(\"{a} {b}\")\n"
"}\n"
"\n"
"pub fn main() {\n"
" println!(\"{}\", helper(\"Hello\", \"World\"));\n"
"}\n"
"\n"
"#[cfg(test)]\n"
"mod tests {\n"
" use super::*;\n"
"\n"
" #[test]\n"
" fn test_helper() {\n"
" assert_eq!(helper(\"foo\", \"bar\"), \"foo bar\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn helper(a: &str, b: &str) -> String {\n"
" format!(\"{a} {b}\")\n"
"}\n"
"\n"
"pub fn main() {\n"
" println!(\"{}\", helper(\"Hello\", \"World\"));\n"
"}\n"
"\n"
"#[cfg(test)]\n"
"mod tests {\n"
" use super::*;\n"
"\n"
" #[test]\n"
" fn test_helper() {\n"
" assert_eq!(helper(\"foo\", \"bar\"), \"foo bar\");\n"
" }\n"
"}\n"
"```"
#: src/testing/test-modules.md:26
msgid "This lets you unit test private helpers."
msgstr ""
"이렇게 서브 모듈로 테스트를 만들면 private한 헬퍼 함수에 대한 단위 테스트도 "
"가능합니다."
#: src/testing/test-modules.md:27
msgid "The `#[cfg(test)]` attribute is only active when you run `cargo test`."
msgstr ""
"`#[cfg(test)]` 어트리뷰트가 추가된 항목은 `cargo test`를 수행했을 경우에만 동"
"작합니다."
#: src/testing/doc-tests.md:3
msgid "Rust has built-in support for documentation tests:"
msgstr "러스트는 문서화주석에 대한 테스트를 내장하여 제공합니다:"
#: src/testing/doc-tests.md:5
msgid ""
"```rust\n"
"/// Shortens a string to the given length.\n"
"///\n"
"/// ```\n"
"/// use playground::shorten_string;\n"
"/// assert_eq!(shorten_string(\"Hello World\", 5), \"Hello\");\n"
"/// assert_eq!(shorten_string(\"Hello World\", 20), \"Hello World\");\n"
"/// ```\n"
"pub fn shorten_string(s: &str, length: usize) -> &str {\n"
" &s[..std::cmp::min(length, s.len())]\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"/// Shortens a string to the given length.\n"
"///\n"
"/// ```\n"
"/// use playground::shorten_string;\n"
"/// assert_eq!(shorten_string(\"Hello World\", 5), \"Hello\");\n"
"/// assert_eq!(shorten_string(\"Hello World\", 20), \"Hello World\");\n"
"/// ```\n"
"pub fn shorten_string(s: &str, length: usize) -> &str {\n"
" &s[..std::cmp::min(length, s.len())]\n"
"}\n"
"```"
#: src/testing/doc-tests.md:18
msgid "Code blocks in `///` comments are automatically seen as Rust code."
msgstr "`///` 주석안의 코드 블록은 자동으로 러스트 코드로 인식됩니다."
#: src/testing/doc-tests.md:19
msgid "The code will be compiled and executed as part of `cargo test`."
msgstr "이 코드 블록은 `cargo test` 호출하면 자동으로 컴파일되고 실행됩니다."
#: src/testing/doc-tests.md:20
msgid ""
"Test the above code on the [Rust Playground](https://play.rust-lang.org/?"
"version=stable&mode=debug&edition=2021&gist=3ce2ad13ea1302f6572cb15cd96becf0)."
msgstr ""
"위 코드를 [Rust Playground](https://play.rust-lang.org/?"
"version=stable&mode=debug&edition=2021&gist=3ce2ad13ea1302f6572cb15cd96becf0)"
"에서 테스트 해 보시기 바랍니다."
#: src/testing/integration-tests.md:3
msgid "If you want to test your library as a client, use an integration test."
msgstr "라이브러리를 사용자 입장에서 테스트 하려면, 통합 테스트를 해야 합니다."
#: src/testing/integration-tests.md:5
msgid "Create a `.rs` file under `tests/`:"
msgstr "`test/`디렉터리 아래에 `.rs`파일을 하나 만드세요:"
#: src/testing/integration-tests.md:7
msgid ""
"```rust,ignore\n"
"use my_library::init;\n"
"\n"
"#[test]\n"
"fn test_init() {\n"
" assert!(init().is_ok());\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"use my_library::init;\n"
"\n"
"#[test]\n"
"fn test_init() {\n"
" assert!(init().is_ok());\n"
"}\n"
"```"
#: src/testing/integration-tests.md:16
msgid "These tests only have access to the public API of your crate."
msgstr "이 테스트는 크레이트의 공개 API에만 접근할 수 있습니다."
#: src/testing/useful-crates.md:1
msgid "Useful crates for writing tests"
msgstr "테스트 작성에 유용한 크레이트"
#: src/testing/useful-crates.md:3
msgid "Rust comes with only basic support for writing tests."
msgstr "러스트는 테스트 작성과 관련해서는 기본적인 기능만 지원합니다."
#: src/testing/useful-crates.md:5
msgid "Here are some additional crates which we recommend for writing tests:"
msgstr "다음은 테스트를 작성할 때 권장되는 추가 크레이트입니다:"
#: src/testing/useful-crates.md:7
msgid ""
"[googletest](https://docs.rs/googletest): Comprehensive test assertion "
"library in the tradition of GoogleTest for C++."
msgstr ""
"[googletest](https://docs.rs/googletest): C++용 GoogleTest의 방식을 따르는 테"
"스트 라이브러리 입니다."
#: src/testing/useful-crates.md:8
msgid "[proptest](https://docs.rs/proptest): Property-based testing for Rust."
msgstr "[proptest](https://docs.rs/proptest): Rust용 속성 기반 테스트입니다."
#: src/testing/useful-crates.md:9
msgid ""
"[rstest](https://docs.rs/rstest): Support for fixtures and parameterised "
"tests."
msgstr ""
"[rstest](https://docs.rs/rstest): 픽스처 및 매개변수화된 테스트를 지원합니다."
#: src/unsafe.md:3
msgid "The Rust language has two parts:"
msgstr "러스트로 작성된 프로그램은 크게 두 부분으로 나뉩니다:"
#: src/unsafe.md:5
msgid "**Safe Rust:** memory safe, no undefined behavior possible."
msgstr ""
"**안전한 러스트:** 메모리 관련 오류 발생 불가능, 정의되지 않은 동작 없음."
#: src/unsafe.md:6
msgid ""
"**Unsafe Rust:** can trigger undefined behavior if preconditions are "
"violated."
msgstr ""
"**안전하지 않은 러스트:** 특별한 조건을 만족하지 않은채로 사용되면 정의되지 "
"않은 동작을 유발할 수 있음."
#: src/unsafe.md:8
msgid ""
"We will be seeing mostly safe Rust in this course, but it's important to "
"know what Unsafe Rust is."
msgstr ""
"이 강의는 대부분 안전한 러스트에 대해 다루지만 안전하지 않은 러스트가 무엇인"
"지는 알아 두어야 합니다."
#: src/unsafe.md:11
msgid ""
"Unsafe code is usually small and isolated, and its correctness should be "
"carefully documented. It is usually wrapped in a safe abstraction layer."
msgstr ""
"보통, 안전하지 않은 러스트 코드는 크기가 작으며, 독립적으로 존재합니다. 그리"
"고 코드가 왜 잘 작동하는지에 대해 세밀하게 문서화가 되어 있습니다. 그리고, 많"
"은 경우 안전한 러스트 코드를 통해서 추상화를 시킨 후 사용하게 됩니다."
#: src/unsafe.md:14
msgid "Unsafe Rust gives you access to five new capabilities:"
msgstr ""
"안전하지 않은 러스트를 이용하면 다음과 같은 다섯 가지 것들이 가능해 집니다:"
#: src/unsafe.md:16
msgid "Dereference raw pointers."
msgstr "원시 포인터 역참조(따라가기)"
#: src/unsafe.md:17
msgid "Access or modify mutable static variables."
msgstr "정적 가변변수 접근 및 수정."
#: src/unsafe.md:18
msgid "Access `union` fields."
msgstr "`union` 필드 접근."
#: src/unsafe.md:19
msgid "Call `unsafe` functions, including `extern` functions."
msgstr "`extern` 함수를 포함한 `unsafe` 함수 호출."
#: src/unsafe.md:20
msgid "Implement `unsafe` traits."
msgstr "`unsafe` 트레잇 구현."
#: src/unsafe.md:22
msgid ""
"We will briefly cover unsafe capabilities next. For full details, please see "
"[Chapter 19.1 in the Rust Book](https://doc.rust-lang.org/book/ch19-01-"
"unsafe-rust.html) and the [Rustonomicon](https://doc.rust-lang.org/nomicon/)."
msgstr ""
"위 기능들에 대해 간략히 살펴보겠습니다. 자세한 내용은 [러스트 프로그래밍 언"
"어, 19.1절](https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html)과 "
"[Rustonomicon](https://doc.rust-lang.org/nomicon/)를 참조하세요."
#: src/unsafe.md:28
msgid ""
"Unsafe Rust does not mean the code is incorrect. It means that developers "
"have turned off the compiler safety features and have to write correct code "
"by themselves. It means the compiler no longer enforces Rust's memory-safety "
"rules."
msgstr ""
"안전하지 않은 러스트라고 해서 코드가 부정확 하다는 뜻은 아닙니다. 여기서 안전"
"하지 않다의 의미는 컴파일러가 제공해주는 안전 장치들이 꺼진 상태이며, 개발자"
"가 스스로 정확하고 안전한 코드를 작성해야 함을 의미합니다. 이는 컴파일러가 "
"더 이상 러스트의 메모리 안전과 관련된 규칙들을 적용하지 않는다는 것입니다."
#: src/unsafe/raw-pointers.md:3
msgid "Creating pointers is safe, but dereferencing them requires `unsafe`:"
msgstr ""
"포인터를 만드는 것은 안전합니다. 하지만 역참조(따라가기)할 경우 `unsafe`가 필"
"요합니다:"
#: src/unsafe/raw-pointers.md:5
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let mut num = 5;\n"
"\n"
" let r1 = &mut num as *mut i32;\n"
" let r2 = r1 as *const i32;\n"
"\n"
" // Safe because r1 and r2 were obtained from references and so are\n"
" // guaranteed to be non-null and properly aligned, the objects "
"underlying\n"
" // the references from which they were obtained are live throughout the\n"
" // whole unsafe block, and they are not accessed either through the\n"
" // references or concurrently through any other pointers.\n"
" unsafe {\n"
" println!(\"r1 is: {}\", *r1);\n"
" *r1 = 10;\n"
" println!(\"r2 is: {}\", *r2);\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let mut num = 5;\n"
"\n"
" let r1 = &mut num as *mut i32;\n"
" let r2 = r1 as *const i32;\n"
"\n"
" // Safe because r1 and r2 were obtained from references and so are\n"
" // guaranteed to be non-null and properly aligned, the objects "
"underlying\n"
" // the references from which they were obtained are live throughout the\n"
" // whole unsafe block, and they are not accessed either through the\n"
" // references or concurrently through any other pointers.\n"
" unsafe {\n"
" println!(\"r1 is: {}\", *r1);\n"
" *r1 = 10;\n"
" println!(\"r2 is: {}\", *r2);\n"
" }\n"
"}\n"
"```"
#: src/unsafe/raw-pointers.md:27
msgid ""
"It is good practice (and required by the Android Rust style guide) to write "
"a comment for each `unsafe` block explaining how the code inside it "
"satisfies the safety requirements of the unsafe operations it is doing."
msgstr ""
"모든 `unsafe` 블록에 대해 왜 그 코드가 안전한지에 대한 설명을 주석으로 다는 "
"것은 좋은 습관입니다(사실 안드로이드의 러스트 스타일 가이드에서는 이게 필수입"
"니다)."
#: src/unsafe/raw-pointers.md:31
msgid ""
"In the case of pointer dereferences, this means that the pointers must be "
"[_valid_](https://doc.rust-lang.org/std/ptr/index.html#safety), i.e.:"
msgstr ""
"포인터 역참조를 할 경우, 포인터가 [_유효_](https://doc.rust-lang.org/std/ptr/"
"index.html#safety)해야 합니다. 예를 들어:"
#: src/unsafe/raw-pointers.md:34
msgid "The pointer must be non-null."
msgstr "포인터는 null이면 안됩니다."
#: src/unsafe/raw-pointers.md:35
msgid ""
"The pointer must be _dereferenceable_ (within the bounds of a single "
"allocated object)."
msgstr ""
"포인터는 따라가기가 가능해야 합니다 (객체의 어느 한 부분을 가리키고 있어야 합"
"니다)."
#: src/unsafe/raw-pointers.md:36
msgid "The object must not have been deallocated."
msgstr "이미 반환된 객체를 가리키면 안됩니다."
#: src/unsafe/raw-pointers.md:37
msgid "There must not be concurrent accesses to the same location."
msgstr "같은 위치에 대해 동시적인 접근이 있으면 안됩니다."
#: src/unsafe/raw-pointers.md:38
msgid ""
"If the pointer was obtained by casting a reference, the underlying object "
"must be live and no reference may be used to access the memory."
msgstr ""
"참조를 캐스팅 해서 포인터를 만들었다면, 그 참조가 가리키는 객체는 살아 있어"
"야 하며, 그 객체의 메모리를 접근하는 참조가 하나도 없어야 합니다."
#: src/unsafe/raw-pointers.md:41
msgid "In most cases the pointer must also be properly aligned."
msgstr "대부분의 경우 포인터는 align되어 있어야 합니다."
#: src/unsafe/mutable-static-variables.md:3
msgid "It is safe to read an immutable static variable:"
msgstr "불변 정적변수를 읽는 것은 안전합니다:"
#: src/unsafe/mutable-static-variables.md:5
msgid ""
"```rust,editable\n"
"static HELLO_WORLD: &str = \"Hello, world!\";\n"
"\n"
"fn main() {\n"
" println!(\"HELLO_WORLD: {HELLO_WORLD}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"static HELLO_WORLD: &str = \"Hello, world!\";\n"
"\n"
"fn main() {\n"
" println!(\"HELLO_WORLD: {HELLO_WORLD}\");\n"
"}\n"
"```"
#: src/unsafe/mutable-static-variables.md:13
msgid ""
"However, since data races can occur, it is unsafe to read and write mutable "
"static variables:"
msgstr ""
"하지만, 데이터 레이스가 발생할 수 있으므로 정적 가변변수를 읽고 쓰는 것은 안"
"전하지 않습니다:"
#: src/unsafe/mutable-static-variables.md:16
msgid ""
"```rust,editable\n"
"static mut COUNTER: u32 = 0;\n"
"\n"
"fn add_to_counter(inc: u32) {\n"
" unsafe { COUNTER += inc; } // Potential data race!\n"
"}\n"
"\n"
"fn main() {\n"
" add_to_counter(42);\n"
"\n"
" unsafe { println!(\"COUNTER: {COUNTER}\"); } // Potential data race!\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"static mut COUNTER: u32 = 0;\n"
"\n"
"fn add_to_counter(inc: u32) {\n"
" unsafe { COUNTER += inc; } // 잠재적 데이터 경합!\n"
"}\n"
"\n"
"fn main() {\n"
" add_to_counter(42);\n"
"\n"
" unsafe { println!(\"COUNTER: {COUNTER}\"); } // 잠재적 데이터 경합!\n"
"}\n"
"```"
#: src/unsafe/mutable-static-variables.md:32
msgid ""
"Using a mutable static is generally a bad idea, but there are some cases "
"where it might make sense in low-level `no_std` code, such as implementing a "
"heap allocator or working with some C APIs."
msgstr ""
"일반적으로 이야기 해서, 정적 가변 변수를 쓰는 것은 좋은 아이디어가 아닙니다. "
"그러나 `no_std`와 같은 저수준 코딩을 할 경우에는 필요하기도 합니다. 예를 들"
"어 힙 할당기를 구현하거나, C API를 사용하는 게 그런 경우입니다."
#: src/unsafe/unions.md:3
msgid "Unions are like enums, but you need to track the active field yourself:"
msgstr ""
"유니온 타입은 열거형(enum)과 비슷하지만, 어떤 필드에 해당하는 값을 가지고 있"
"는지 여부를 프로그래머가 수동으로 추적해야 합니다:"
#: src/unsafe/unions.md:5
msgid ""
"```rust,editable\n"
"#[repr(C)]\n"
"union MyUnion {\n"
" i: u8,\n"
" b: bool,\n"
"}\n"
"\n"
"fn main() {\n"
" let u = MyUnion { i: 42 };\n"
" println!(\"int: {}\", unsafe { u.i });\n"
" println!(\"bool: {}\", unsafe { u.b }); // Undefined behavior!\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"#[repr(C)]\n"
"union MyUnion {\n"
" i: u8,\n"
" b: bool,\n"
"}\n"
"\n"
"fn main() {\n"
" let u = MyUnion { i: 42 };\n"
" println!(\"int: {}\", unsafe { u.i });\n"
" println!(\"bool: {}\", unsafe { u.b }); // Undefined behavior!\n"
"}\n"
"```"
#: src/unsafe/unions.md:21
msgid ""
"Unions are very rarely needed in Rust as you can usually use an enum. They "
"are occasionally needed for interacting with C library APIs."
msgstr ""
"러스트에는 열거형이 있기 때문에 유니온이 필요한 경우는 극히 드뭅니다. 유니온"
"은 C 라이브러리 API를 사용할 때 가끔 필요합니다."
#: src/unsafe/unions.md:24
msgid ""
"If you just want to reinterpret bytes as a different type, you probably want "
"[`std::mem::transmute`](https://doc.rust-lang.org/stable/std/mem/fn."
"transmute.html) or a safe wrapper such as the [`zerocopy`](https://crates.io/"
"crates/zerocopy) crate."
msgstr ""
"바이트들을 특정 타입으로 재해석 하고 싶다면 [`std::mem::transmute`](https://"
"doc.rust-lang.org/stable/std/mem/fn.transmute.html)나 좀 더 안전한 "
"[`zerocopy`](https://crates.io/crates/zerocopy) 크레이트를 사용하세요."
#: src/unsafe/calling-unsafe-functions.md:3
msgid ""
"A function or method can be marked `unsafe` if it has extra preconditions "
"you must uphold to avoid undefined behaviour:"
msgstr ""
"함수나 메서드가 정의되지 않은 동작으로 빠지지 않게 하기 위해서 만족해야 하는 "
"전제 조건이 있는 경우, 그 함수나 메서드를 `unsafe`로 표시할 수 있습니다:"
#: src/unsafe/calling-unsafe-functions.md:6
msgid ""
"```rust,editable\n"
"fn main() {\n"
" let emojis = \"🗻∈🌏\";\n"
"\n"
" // Safe because the indices are in the correct order, within the bounds "
"of\n"
" // the string slice, and lie on UTF-8 sequence boundaries.\n"
" unsafe {\n"
" println!(\"emoji: {}\", emojis.get_unchecked(0..4));\n"
" println!(\"emoji: {}\", emojis.get_unchecked(4..7));\n"
" println!(\"emoji: {}\", emojis.get_unchecked(7..11));\n"
" }\n"
"\n"
" println!(\"char count: {}\", count_chars(unsafe { emojis."
"get_unchecked(0..7) }));\n"
"\n"
" // Not upholding the UTF-8 encoding requirement breaks memory safety!\n"
" // println!(\"emoji: {}\", unsafe { emojis.get_unchecked(0..3) });\n"
" // println!(\"char count: {}\", count_chars(unsafe { emojis."
"get_unchecked(0..3) }));\n"
"}\n"
"\n"
"fn count_chars(s: &str) -> usize {\n"
" s.chars().map(|_| 1).sum()\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"fn main() {\n"
" let emojis = \"🗻∈🌏\";\n"
"\n"
" // Safe because the indices are in the correct order, within the bounds "
"of\n"
" // the string slice, and lie on UTF-8 sequence boundaries.\n"
" unsafe {\n"
" println!(\"emoji: {}\", emojis.get_unchecked(0..4));\n"
" println!(\"emoji: {}\", emojis.get_unchecked(4..7));\n"
" println!(\"emoji: {}\", emojis.get_unchecked(7..11));\n"
" }\n"
"\n"
" println!(\"char count: {}\", count_chars(unsafe { emojis."
"get_unchecked(0..7) }));\n"
"\n"
" // Not upholding the UTF-8 encoding requirement breaks memory safety!\n"
" // println!(\"emoji: {}\", unsafe { emojis.get_unchecked(0..3) });\n"
" // println!(\"char count: {}\", count_chars(unsafe { emojis."
"get_unchecked(0..3) }));\n"
"}\n"
"\n"
"fn count_chars(s: &str) -> usize {\n"
" s.chars().map(|_| 1).sum()\n"
"}\n"
"```"
#: src/unsafe/writing-unsafe-functions.md:3
msgid ""
"You can mark your own functions as `unsafe` if they require particular "
"conditions to avoid undefined behaviour."
msgstr ""
"여러분이 작성한 함수를 사용할 때 어떤 특별한 조건을 만족해야 한다면, `unsafe`"
"로 마킹할 수 있습니다."
#: src/unsafe/writing-unsafe-functions.md:6
msgid ""
"```rust,editable\n"
"/// Swaps the values pointed to by the given pointers.\n"
"///\n"
"/// # Safety\n"
"///\n"
"/// The pointers must be valid and properly aligned.\n"
"unsafe fn swap(a: *mut u8, b: *mut u8) {\n"
" let temp = *a;\n"
" *a = *b;\n"
" *b = temp;\n"
"}\n"
"\n"
"fn main() {\n"
" let mut a = 42;\n"
" let mut b = 66;\n"
"\n"
" // Safe because ...\n"
" unsafe {\n"
" swap(&mut a, &mut b);\n"
" }\n"
"\n"
" println!(\"a = {}, b = {}\", a, b);\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"/// Swaps the values pointed to by the given pointers.\n"
"///\n"
"/// # Safety\n"
"///\n"
"/// The pointers must be valid and properly aligned.\n"
"unsafe fn swap(a: *mut u8, b: *mut u8) {\n"
" let temp = *a;\n"
" *a = *b;\n"
" *b = temp;\n"
"}\n"
"\n"
"fn main() {\n"
" let mut a = 42;\n"
" let mut b = 66;\n"
"\n"
" // Safe because ...\n"
" unsafe {\n"
" swap(&mut a, &mut b);\n"
" }\n"
"\n"
" println!(\"a = {}, b = {}\", a, b);\n"
"}\n"
"```"
#: src/unsafe/writing-unsafe-functions.md:33
msgid ""
"We wouldn't actually use pointers for this because it can be done safely "
"with references."
msgstr ""
"참조를 사용하면 안전하게 구현할 수 있기 때문에, 실제로 포인터를 사용할 필요"
"는 없습니다."
#: src/unsafe/writing-unsafe-functions.md:35
msgid ""
"Note that unsafe code is allowed within an unsafe function without an "
"`unsafe` block. We can prohibit this with `#[deny(unsafe_op_in_unsafe_fn)]`. "
"Try adding it and see what happens."
msgstr ""
"안전하지 않은(unsafe) 코드가 안전하지 않은(unsafe) 함수의 내부에서 호출될 경"
"우에는 `unsafe`블록을 지정하지 않아도 됩니다. `unsafe`블록을 항상 지정하도록 "
"하고 싶다면 `#[deny(unsafe_op_in_unsafe_fn)]`를 이용하세요. 이 어트리뷰트를 "
"추가해 보고 어떤 일이 일어나는지 확인해 보세요."
#: src/unsafe/extern-functions.md:1
msgid "Calling External Code"
msgstr "외부 코드 호출"
#: src/unsafe/extern-functions.md:3
msgid ""
"Functions from other languages might violate the guarantees of Rust. Calling "
"them is thus unsafe:"
msgstr ""
"다른 언어의 함수는 러스트의 보증을 위반할 수 있습니다. 따라서 이를 호출하는 "
"것은 안전하지 않습니다:"
#: src/unsafe/extern-functions.md:6
msgid ""
"```rust,editable\n"
"extern \"C\" {\n"
" fn abs(input: i32) -> i32;\n"
"}\n"
"\n"
"fn main() {\n"
" unsafe {\n"
" // Undefined behavior if abs misbehaves.\n"
" println!(\"Absolute value of -3 according to C: {}\", abs(-3));\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"extern \"C\" {\n"
" fn abs(input: i32) -> i32;\n"
"}\n"
"\n"
"fn main() {\n"
" unsafe {\n"
" // Undefined behavior if abs misbehaves.\n"
" println!(\"Absolute value of -3 according to C: {}\", abs(-3));\n"
" }\n"
"}\n"
"```"
#: src/unsafe/extern-functions.md:21
msgid ""
"This is usually only a problem for extern functions which do things with "
"pointers which might violate Rust's memory model, but in general any C "
"function might have undefined behaviour under any arbitrary circumstances."
msgstr ""
"이게 문제가 되는 경우는 대부분 외부 함수가 러스트의 메모리 모델을 위반하고 있"
"을 경우입니다. 그러나 어떤 C함수라도 어떤 임의의 상황에서는 정의되지 않은 동"
"작을 할 수 있기 때문에, 엄밀히 말해서는 모든 외부 함수에 대해서 문제입니다."
#: src/unsafe/extern-functions.md:25
msgid ""
"The `\"C\"` in this example is the ABI; [other ABIs are available too]"
"(https://doc.rust-lang.org/reference/items/external-blocks.html)."
msgstr ""
"위 예제 코드에서 `\"C\"`는 ABI를 의미합니다. [다른 ABI도 있습니다.](https://"
"doc.rust-lang.org/reference/items/external-blocks.html)"
#: src/unsafe/unsafe-traits.md:3
msgid ""
"Like with functions, you can mark a trait as `unsafe` if the implementation "
"must guarantee particular conditions to avoid undefined behaviour."
msgstr ""
"함수에서와 마찬가지로 트레잇도 `unsafe`로 마킹 가능합니다. 만약 그 트레잇을 "
"구현할 때 정의되지 않은 동작을 피하기 위해 특별한 조건이 필요하다면 말이지요."
#: src/unsafe/unsafe-traits.md:6
msgid ""
"For example, the `zerocopy` crate has an unsafe trait that looks [something "
"like this](https://docs.rs/zerocopy/latest/zerocopy/trait.AsBytes.html):"
msgstr ""
"예를 들어 `zerocopy` 크레이트에는 [안전하지 않은 트레잇](https://docs.rs/"
"zerocopy/latest/zerocopy/trait.AsBytes.html)이 있습니다:"
#: src/unsafe/unsafe-traits.md:9
msgid ""
"```rust,editable\n"
"use std::mem::size_of_val;\n"
"use std::slice;\n"
"\n"
"/// ...\n"
"/// # Safety\n"
"/// The type must have a defined representation and no padding.\n"
"pub unsafe trait AsBytes {\n"
" fn as_bytes(&self) -> &[u8] {\n"
" unsafe {\n"
" slice::from_raw_parts(self as *const Self as *const u8, "
"size_of_val(self))\n"
" }\n"
" }\n"
"}\n"
"\n"
"// Safe because u32 has a defined representation and no padding.\n"
"unsafe impl AsBytes for u32 {}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::mem::size_of_val;\n"
"use std::slice;\n"
"\n"
"/// ...\n"
"/// # Safety\n"
"/// The type must have a defined representation and no padding.\n"
"pub unsafe trait AsBytes {\n"
" fn as_bytes(&self) -> &[u8] {\n"
" unsafe {\n"
" slice::from_raw_parts(self as *const Self as *const u8, "
"size_of_val(self))\n"
" }\n"
" }\n"
"}\n"
"\n"
"// Safe because u32 has a defined representation and no padding.\n"
"unsafe impl AsBytes for u32 {}\n"
"```"
#: src/unsafe/unsafe-traits.md:30
msgid ""
"There should be a `# Safety` section on the Rustdoc for the trait explaining "
"the requirements for the trait to be safely implemented."
msgstr ""
"안전하지 않은 트레잇을 만들 때에는 주석에 `# Safety` 항목이 있어서 이 트레잇"
"을 안전하게 구현하려면 어떤 요구사항들을 만족해야 하는지를 설명해야 합니다."
#: src/unsafe/unsafe-traits.md:33
msgid ""
"The actual safety section for `AsBytes` is rather longer and more "
"complicated."
msgstr ""
"`AsBytes`에서 지켜야 할 안전성에 대한 실제 설명은 좀 더 길고 복잡합니다."
#: src/unsafe/unsafe-traits.md:35
msgid "The built-in `Send` and `Sync` traits are unsafe."
msgstr "빌트인 트레잇인 `Send`와 `Sync`는 안전하지 않은 트레잇 입니다."
#: src/exercises/day-3/afternoon.md:1
msgid "Day 3: Afternoon Exercises"
msgstr "3일차 오후 연습문제"
#: src/exercises/day-3/afternoon.md:3
msgid "Let us build a safe wrapper for reading directory content!"
msgstr "디렉터리의 내용을 읽는 안전한 래퍼 코드를 작성해 봅시다!"
#: src/exercises/day-3/afternoon.md:5
msgid ""
"For this exercise, we suggest using a local dev environment instead of the "
"Playground. This will allow you to run your binary on your own machine."
msgstr ""
"이번 연습에서는, 플레이그라운드 대신 로컬 개발 환경을 사용해서, 여러분의 컴퓨"
"터에서 바이너리를 직접 수행해 보세요."
#: src/exercises/day-3/afternoon.md:8
msgid ""
"To get started, follow the [running locally](../../cargo/running-locally.md) "
"instructions."
msgstr ""
"시작하기 위해, [로컬 환경에서 수행하기](../../cargo/running-locally.md)를 따"
"르세요."
#: src/exercises/day-3/afternoon.md:14
msgid ""
"After looking at the exercise, you can look at the [solution](solutions-"
"afternoon.md) provided."
msgstr ""
"연습문제를 살펴 본 후, 제공된 [해답](solutions-afternoon.md)을 살펴볼 수 있습"
"니다."
#: src/exercises/day-3/safe-ffi-wrapper.md:3
msgid ""
"Rust has great support for calling functions through a _foreign function "
"interface_ (FFI). We will use this to build a safe wrapper for the `libc` "
"functions you would use from C to read the filenames of a directory."
msgstr ""
"러스트는 \\_외부 기능 호출(FFI)\\_을 지원합니다. 우리는 이를 이용하여 디렉터"
"리에서 파일 이름을 읽어오는 `libc` 함수에 대한 안전한 래퍼를 만들 것입니다."
#: src/exercises/day-3/safe-ffi-wrapper.md:7
msgid "You will want to consult the manual pages:"
msgstr "아래 리눅스 메뉴얼 문서들을 참조하시기 바랍니다:"
#: src/exercises/day-3/safe-ffi-wrapper.md:9
msgid "[`opendir(3)`](https://man7.org/linux/man-pages/man3/opendir.3.html)"
msgstr "[`opendir(3)`](https://man7.org/linux/man-pages/man3/opendir.3.html)"
#: src/exercises/day-3/safe-ffi-wrapper.md:10
msgid "[`readdir(3)`](https://man7.org/linux/man-pages/man3/readdir.3.html)"
msgstr "[`readdir(3)`](https://man7.org/linux/man-pages/man3/readdir.3.html)"
#: src/exercises/day-3/safe-ffi-wrapper.md:11
msgid "[`closedir(3)`](https://man7.org/linux/man-pages/man3/closedir.3.html)"
msgstr "[`closedir(3)`](https://man7.org/linux/man-pages/man3/closedir.3.html)"
#: src/exercises/day-3/safe-ffi-wrapper.md:13
msgid ""
"You will also want to browse the [`std::ffi`](https://doc.rust-lang.org/std/"
"ffi/) module. There you find a number of string types which you need for the "
"exercise:"
msgstr ""
"아마 [`std::ffi`](https://doc.rust-lang.org/std/ffi/)모듈을 참조할 필요가 있"
"을 것입니다. 거기에는 이번 예제를 수행하는데 필요한 다양한 종류의 문자열 타입"
"들이 소개되어 있습니다:"
#: src/exercises/day-3/safe-ffi-wrapper.md:16
msgid "Encoding"
msgstr "인코딩"
#: src/exercises/day-3/safe-ffi-wrapper.md:16
msgid "Use"
msgstr "사용"
#: src/exercises/day-3/safe-ffi-wrapper.md:18
msgid ""
"[`str`](https://doc.rust-lang.org/std/primitive.str.html) and [`String`]"
"(https://doc.rust-lang.org/std/string/struct.String.html)"
msgstr ""
"[`str`](https://doc.rust-lang.org/std/primitive.str.html)과 [`String`]"
"(https://doc.rust-lang.org/std/string/struct.String.html)"
#: src/exercises/day-3/safe-ffi-wrapper.md:18
msgid "UTF-8"
msgstr "UTF-8"
#: src/exercises/day-3/safe-ffi-wrapper.md:18
msgid "Text processing in Rust"
msgstr "러스트에서의 문자열 처리"
#: src/exercises/day-3/safe-ffi-wrapper.md:19
msgid ""
"[`CStr`](https://doc.rust-lang.org/std/ffi/struct.CStr.html) and [`CString`]"
"(https://doc.rust-lang.org/std/ffi/struct.CString.html)"
msgstr ""
"[`CStr`](https://doc.rust-lang.org/std/ffi/struct.CStr.html)과 [`CString`]"
"(https://doc.rust-lang.org/std/ffi/struct.CString.html)"
#: src/exercises/day-3/safe-ffi-wrapper.md:19
msgid "NUL-terminated"
msgstr "널(NUL)로 끝남"
#: src/exercises/day-3/safe-ffi-wrapper.md:19
msgid "Communicating with C functions"
msgstr "C함수와 연동하기"
#: src/exercises/day-3/safe-ffi-wrapper.md:20
msgid ""
"[`OsStr`](https://doc.rust-lang.org/std/ffi/struct.OsStr.html) and "
"[`OsString`](https://doc.rust-lang.org/std/ffi/struct.OsString.html)"
msgstr ""
"[`OsStr`](https://doc.rust-lang.org/std/ffi/struct.OsStr.html)와 [`OsString`]"
"(https://doc.rust-lang.org/std/ffi/struct.OsString.html)"
#: src/exercises/day-3/safe-ffi-wrapper.md:20
msgid "OS-specific"
msgstr "OS가 정의함"
#: src/exercises/day-3/safe-ffi-wrapper.md:20
msgid "Communicating with the OS"
msgstr "OS와 연동하기 위한 문자열"
#: src/exercises/day-3/safe-ffi-wrapper.md:22
msgid "You will convert between all these types:"
msgstr "이 타입들 간의 변환은 다음과 같습니다:"
#: src/exercises/day-3/safe-ffi-wrapper.md:24
msgid ""
"`&str` to `CString`: you need to allocate space for a trailing `\\0` "
"character,"
msgstr ""
"`&str`에서 `CString`으로의 변환: 맨 마지막의 `\\0` 문자를 저장하기 위한 공간"
"을 할당해야 합니다,"
#: src/exercises/day-3/safe-ffi-wrapper.md:25
msgid "`CString` to `*const i8`: you need a pointer to call C functions,"
msgstr ""
"`CString`에서 `*const i8`로의 변환: C함수를 호출하기 위해서는 포인터가 필요합"
"니다,"
#: src/exercises/day-3/safe-ffi-wrapper.md:26
msgid ""
"`*const i8` to `&CStr`: you need something which can find the trailing `\\0` "
"character,"
msgstr ""
"`*const i8`에서 `&CStr`로의 변환: 주어진 바이트 시퀀스가 `\\0`로 끝나는지 확"
"인하고 싶은 경우,"
#: src/exercises/day-3/safe-ffi-wrapper.md:27
msgid ""
"`&CStr` to `&[u8]`: a slice of bytes is the universal interface for \"some "
"unknow data\","
msgstr ""
"`&CStr`에서 `&[u8]`로의 변환: 바이트 슬라이스는 \"알수없는 데이터\"에 대한 일"
"반적인 인터페이스입니다,"
#: src/exercises/day-3/safe-ffi-wrapper.md:28
msgid ""
"`&[u8]` to `&OsStr`: `&OsStr` is a step towards `OsString`, use [`OsStrExt`]"
"(https://doc.rust-lang.org/std/os/unix/ffi/trait.OsStrExt.html) to create it,"
msgstr ""
"`&[u8]`에서 `&OsStr`로의 변환: `&OsStr`는 `OsString`으로 가기 위한 중간 단계 "
"입니다. [`OsStrExt`](https://doc.rust-lang.org/std/os/unix/ffi/trait."
"OsStrExt.html)를 사용해서 `OsStr`를 생성하세요,"
#: src/exercises/day-3/safe-ffi-wrapper.md:31
msgid ""
"`&OsStr` to `OsString`: you need to clone the data in `&OsStr` to be able to "
"return it and call `readdir` again."
msgstr ""
"`&OsStr`에서 `OsString`으로의 변환: `&OsStr`이 가리키고 있는 데이터를 복사함"
"으로써, 이 데이터를 리턴하고, `readdir`함수를 호출할 때 사용할 수 있게 해 줍"
"니다."
#: src/exercises/day-3/safe-ffi-wrapper.md:34
msgid ""
"The [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html) also has a very "
"useful chapter about FFI."
msgstr ""
"[Nomicon](https://doc.rust-lang.org/nomicon/ffi.html)에 FFI와 관련한 아주 유"
"용한 챕터가 있습니다."
#: src/exercises/day-3/safe-ffi-wrapper.md:45
msgid ""
"Copy the code below to <https://play.rust-lang.org/> and fill in the missing "
"functions and methods:"
msgstr ""
"아래 코드를 <https://play.rust-lang.org/>에 복사하고 빠진 함수와 메서드를 채"
"워봅니다:"
#: src/exercises/day-3/safe-ffi-wrapper.md:48
msgid ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_imports, unused_variables, dead_code)]\n"
"\n"
"mod ffi {\n"
" use std::os::raw::{c_char, c_int};\n"
" #[cfg(not(target_os = \"macos\"))]\n"
" use std::os::raw::{c_long, c_ulong, c_ushort, c_uchar};\n"
"\n"
" // Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.\n"
" #[repr(C)]\n"
" pub struct DIR {\n"
" _data: [u8; 0],\n"
" _marker: core::marker::PhantomData<(*mut u8, core::marker::"
"PhantomPinned)>,\n"
" }\n"
"\n"
" // Layout according to the Linux man page for readdir(3), where ino_t "
"and\n"
" // off_t are resolved according to the definitions in\n"
" // /usr/include/x86_64-linux-gnu/{sys/types.h, bits/typesizes.h}.\n"
" #[cfg(not(target_os = \"macos\"))]\n"
" #[repr(C)]\n"
" pub struct dirent {\n"
" pub d_ino: c_ulong,\n"
" pub d_off: c_long,\n"
" pub d_reclen: c_ushort,\n"
" pub d_type: c_uchar,\n"
" pub d_name: [c_char; 256],\n"
" }\n"
"\n"
" // Layout according to the macOS man page for dir(5).\n"
" #[cfg(all(target_os = \"macos\"))]\n"
" #[repr(C)]\n"
" pub struct dirent {\n"
" pub d_fileno: u64,\n"
" pub d_seekoff: u64,\n"
" pub d_reclen: u16,\n"
" pub d_namlen: u16,\n"
" pub d_type: u8,\n"
" pub d_name: [c_char; 1024],\n"
" }\n"
"\n"
" extern \"C\" {\n"
" pub fn opendir(s: *const c_char) -> *mut DIR;\n"
"\n"
" #[cfg(not(all(target_os = \"macos\", target_arch = \"x86_64\")))]\n"
" pub fn readdir(s: *mut DIR) -> *const dirent;\n"
"\n"
" // See https://github.com/rust-lang/libc/issues/414 and the section "
"on\n"
" // _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).\n"
" //\n"
" // \"Platforms that existed before these updates were available\" "
"refers\n"
" // to macOS (as opposed to iOS / wearOS / etc.) on Intel and "
"PowerPC.\n"
" #[cfg(all(target_os = \"macos\", target_arch = \"x86_64\"))]\n"
" #[link_name = \"readdir$INODE64\"]\n"
" pub fn readdir(s: *mut DIR) -> *const dirent;\n"
"\n"
" pub fn closedir(s: *mut DIR) -> c_int;\n"
" }\n"
"}\n"
"\n"
"use std::ffi::{CStr, CString, OsStr, OsString};\n"
"use std::os::unix::ffi::OsStrExt;\n"
"\n"
"#[derive(Debug)]\n"
"struct DirectoryIterator {\n"
" path: CString,\n"
" dir: *mut ffi::DIR,\n"
"}\n"
"\n"
"impl DirectoryIterator {\n"
" fn new(path: &str) -> Result<DirectoryIterator, String> {\n"
" // Call opendir and return a Ok value if that worked,\n"
" // otherwise return Err with a message.\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Iterator for DirectoryIterator {\n"
" type Item = OsString;\n"
" fn next(&mut self) -> Option<OsString> {\n"
" // Keep calling readdir until we get a NULL pointer back.\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Drop for DirectoryIterator {\n"
" fn drop(&mut self) {\n"
" // Call closedir as needed.\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"fn main() -> Result<(), String> {\n"
" let iter = DirectoryIterator::new(\".\")?;\n"
" println!(\"files: {:#?}\", iter.collect::<Vec<_>>());\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
"```rust,should_panic\n"
"// TODO: remove this when you're done with your implementation.\n"
"#![allow(unused_imports, unused_variables, dead_code)]\n"
"\n"
"mod ffi {\n"
" use std::os::raw::{c_char, c_int};\n"
" #[cfg(not(target_os = \"macos\"))]\n"
" use std::os::raw::{c_long, c_ulong, c_ushort, c_uchar};\n"
"\n"
" // Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.\n"
" #[repr(C)]\n"
" pub struct DIR {\n"
" _data: [u8; 0],\n"
" _marker: core::marker::PhantomData<(*mut u8, core::marker::"
"PhantomPinned)>,\n"
" }\n"
"\n"
" // Layout according to the Linux man page for readdir(3), where ino_t "
"and\n"
" // off_t are resolved according to the definitions in\n"
" // /usr/include/x86_64-linux-gnu/{sys/types.h, bits/typesizes.h}.\n"
" #[cfg(not(target_os = \"macos\"))]\n"
" #[repr(C)]\n"
" pub struct dirent {\n"
" pub d_ino: c_ulong,\n"
" pub d_off: c_long,\n"
" pub d_reclen: c_ushort,\n"
" pub d_type: c_uchar,\n"
" pub d_name: [c_char; 256],\n"
" }\n"
"\n"
" // Layout according to the macOS man page for dir(5).\n"
" #[cfg(all(target_os = \"macos\"))]\n"
" #[repr(C)]\n"
" pub struct dirent {\n"
" pub d_fileno: u64,\n"
" pub d_seekoff: u64,\n"
" pub d_reclen: u16,\n"
" pub d_namlen: u16,\n"
" pub d_type: u8,\n"
" pub d_name: [c_char; 1024],\n"
" }\n"
"\n"
" extern \"C\" {\n"
" pub fn opendir(s: *const c_char) -> *mut DIR;\n"
"\n"
" #[cfg(not(all(target_os = \"macos\", target_arch = \"x86_64\")))]\n"
" pub fn readdir(s: *mut DIR) -> *const dirent;\n"
"\n"
" // See https://github.com/rust-lang/libc/issues/414 and the section "
"on\n"
" // _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).\n"
" //\n"
" // \"Platforms that existed before these updates were available\" "
"refers\n"
" // to macOS (as opposed to iOS / wearOS / etc.) on Intel and "
"PowerPC.\n"
" #[cfg(all(target_os = \"macos\", target_arch = \"x86_64\"))]\n"
" #[link_name = \"readdir$INODE64\"]\n"
" pub fn readdir(s: *mut DIR) -> *const dirent;\n"
"\n"
" pub fn closedir(s: *mut DIR) -> c_int;\n"
" }\n"
"}\n"
"\n"
"use std::ffi::{CStr, CString, OsStr, OsString};\n"
"use std::os::unix::ffi::OsStrExt;\n"
"\n"
"#[derive(Debug)]\n"
"struct DirectoryIterator {\n"
" path: CString,\n"
" dir: *mut ffi::DIR,\n"
"}\n"
"\n"
"impl DirectoryIterator {\n"
" fn new(path: &str) -> Result<DirectoryIterator, String> {\n"
" // Call opendir and return a Ok value if that worked,\n"
" // otherwise return Err with a message.\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Iterator for DirectoryIterator {\n"
" type Item = OsString;\n"
" fn next(&mut self) -> Option<OsString> {\n"
" // Keep calling readdir until we get a NULL pointer back.\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"impl Drop for DirectoryIterator {\n"
" fn drop(&mut self) {\n"
" // Call closedir as needed.\n"
" unimplemented!()\n"
" }\n"
"}\n"
"\n"
"fn main() -> Result<(), String> {\n"
" let iter = DirectoryIterator::new(\".\")?;\n"
" println!(\"files: {:#?}\", iter.collect::<Vec<_>>());\n"
" Ok(())\n"
"}\n"
"```"
#: src/android.md:1
#, fuzzy
msgid "Welcome to Rust in Android"
msgstr "1일차 개요"
#: src/android.md:3
msgid ""
"Rust is supported for native platform development on Android. This means "
"that you can write new operating system services in Rust, as well as "
"extending existing services."
msgstr ""
"러스트는 안드로이드 네이티브 플랫폼 개발을 지원합니다. 기존의 OS 서비스를 확"
"장하거나, 새로운 서비스를 만드는데 러스트를 쓸 수 있습니다."
#: src/android.md:7
msgid ""
"We will attempt to call Rust from one of your own projects today. So try to "
"find a little corner of your code base where we can move some lines of code "
"to Rust. The fewer dependencies and \"exotic\" types the better. Something "
"that parses some raw bytes would be ideal."
msgstr ""
"우리는 오늘 여러분의 프로젝트에서 러스트 코드를 호출해볼 것입니다. 그 프로젝"
"트에서 러스트로 옮길만 한 작은 부분을 정하세요. 의존성이 적고 \"특이한\" 타입"
"이 적을 수록 좋습니다. 바이트 몇 개를 파싱하는 코드라면 완벽합니다."
#: src/android/setup.md:3
msgid ""
"We will be using an Android Virtual Device to test our code. Make sure you "
"have access to one or create a new one with:"
msgstr ""
"안드로이드 가상 디바이스(Android Virtual Device)를 사용하여 여러분의 코드를 "
"수행할 겁니다. 새로운 가상 디바이스를 생성하려면 아래의 명령어를 사용하세요:"
#: src/android/setup.md:6
#, fuzzy
msgid ""
"```shell\n"
"source build/envsetup.sh\n"
"lunch aosp_cf_x86_64_phone-userdebug\n"
"acloud create\n"
"```"
msgstr ""
"```shell\n"
"$ source build/envsetup.sh\n"
"$ lunch aosp_cf_x86_64_phone-userdebug\n"
"$ acloud create\n"
"```"
#: src/android/setup.md:12
msgid ""
"Please see the [Android Developer Codelab](https://source.android.com/docs/"
"setup/start) for details."
msgstr ""
"자세한 내용은 [Android Developer Codelab](https://source.android.com/docs/"
"setup/start)을 참조하십시오."
#: src/android/build-rules.md:3
msgid "The Android build system (Soong) supports Rust via a number of modules:"
msgstr ""
"안드로이드 빌드 시스템(Soong)은 다음과 같은 여러 모듈을 통해 러스트를 지원합"
"니다:"
#: src/android/build-rules.md:5
msgid "Module Type"
msgstr "Module Type"
#: src/android/build-rules.md:5
msgid "Description"
msgstr "Description"
#: src/android/build-rules.md:7
msgid "`rust_binary`"
msgstr "`rust_binary`"
#: src/android/build-rules.md:7
msgid "Produces a Rust binary."
msgstr "러스트 바이너리를 생성합니다."
#: src/android/build-rules.md:8
msgid "`rust_library`"
msgstr "`rust_library`"
#: src/android/build-rules.md:8
msgid "Produces a Rust library, and provides both `rlib` and `dylib` variants."
msgstr "러스트 라이브러리(rlib혹은 dylib)를 생성합니다."
#: src/android/build-rules.md:9
msgid "`rust_ffi`"
msgstr "`rust_ffi`"
#: src/android/build-rules.md:9
msgid ""
"Produces a Rust C library usable by `cc` modules, and provides both static "
"and shared variants."
msgstr "cc 모듈에서 사용할 수 있는 C library (정적 혹은 동적)를 생성합니다."
#: src/android/build-rules.md:10
msgid "`rust_proc_macro`"
msgstr "`rust_proc_macro`"
#: src/android/build-rules.md:10
msgid ""
"Produces a `proc-macro` Rust library. These are analogous to compiler "
"plugins."
msgstr ""
"`proc-macro`를 구현하는 러스트 라이브러리를 생성합니다. 컴파일러의 플러그인으"
"로 생각해도 좋습니다."
#: src/android/build-rules.md:11
msgid "`rust_test`"
msgstr "`rust_test`"
#: src/android/build-rules.md:11
msgid "Produces a Rust test binary that uses the standard Rust test harness."
msgstr "표준 러스트 테스트 러너를 사용하는 테스트 바이너리를 생성합니다."
#: src/android/build-rules.md:12
msgid "`rust_fuzz`"
msgstr "`rust_fuzz`"
#: src/android/build-rules.md:12
msgid "Produces a Rust fuzz binary leveraging `libfuzzer`."
msgstr "`libfuzzer`를 사용하여 fuzz 바이너리를 생성합니다."
#: src/android/build-rules.md:13
msgid "`rust_protobuf`"
msgstr "`rust_protobuf`"
#: src/android/build-rules.md:13
msgid ""
"Generates source and produces a Rust library that provides an interface for "
"a particular protobuf."
msgstr ""
"프로토버프(protobuf) 인터페이스를 제공하는 러스트 라이브러리를 생성합니다."
#: src/android/build-rules.md:14
msgid "`rust_bindgen`"
msgstr "`rust_bindgen`"
#: src/android/build-rules.md:14
msgid ""
"Generates source and produces a Rust library containing Rust bindings to C "
"libraries."
msgstr ""
"C 라이브러리에 대한 러스트 바인딩을 제공하는 러스트 라이브러리를 생성합니다."
#: src/android/build-rules.md:16
msgid "We will look at `rust_binary` and `rust_library` next."
msgstr "다음은 `rust_binary`와 `rust_library`를 살펴봅니다."
#: src/android/build-rules/binary.md:1
msgid "Rust Binaries"
msgstr "러스트 바이너리"
#: src/android/build-rules/binary.md:3
msgid ""
"Let us start with a simple application. At the root of an AOSP checkout, "
"create the following files:"
msgstr ""
"간단한 응용 프로그램으로 시작해 보겠습니다. AOSP 체크아웃의 루트에서 다음 파"
"일을 생성합니다:"
#: src/android/build-rules/binary.md:6 src/android/build-rules/library.md:13
msgid "_hello_rust/Android.bp_:"
msgstr "_hello_rust/Android.bp_:"
#: src/android/build-rules/binary.md:8
msgid ""
"```javascript\n"
"rust_binary {\n"
" name: \"hello_rust\",\n"
" crate_name: \"hello_rust\",\n"
" srcs: [\"src/main.rs\"],\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_binary {\n"
" name: \"hello_rust\",\n"
" crate_name: \"hello_rust\",\n"
" srcs: [\"src/main.rs\"],\n"
"}\n"
"```"
#: src/android/build-rules/binary.md:16 src/android/build-rules/library.md:34
msgid "_hello_rust/src/main.rs_:"
msgstr "_hello_rust/src/main.rs_:"
#: src/android/build-rules/binary.md:18
msgid ""
"```rust\n"
"//! Rust demo.\n"
"\n"
"/// Prints a greeting to standard output.\n"
"fn main() {\n"
" println!(\"Hello from Rust!\");\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"//! Rust 데모입니다.\n"
"\n"
"/// 인사말을 표준 출력으로 인쇄합니다.\n"
"fn main() {\n"
" println!(\"Hello from Rust!\");\n"
"}\n"
"```"
#: src/android/build-rules/binary.md:27
msgid "You can now build, push, and run the binary:"
msgstr "그런 다음, 이 바이너리를 빌드하고, 가상 디바이스에 넣고, 실행합니다:"
#: src/android/build-rules/binary.md:29
#, fuzzy
msgid ""
"```shell\n"
"m hello_rust\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/hello_rust /data/local/tmp\"\n"
"adb shell /data/local/tmp/hello_rust\n"
"```"
msgstr ""
"```shell\n"
"$ m hello_rust_logs\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/hello_rust_logs /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/hello_rust_logs\n"
"```"
#: src/android/build-rules/binary.md:35
msgid ""
"```text\n"
"Hello from Rust!\n"
"```"
msgstr ""
#: src/android/build-rules/library.md:1
msgid "Rust Libraries"
msgstr "러스트 라이브러리"
#: src/android/build-rules/library.md:3
msgid "You use `rust_library` to create a new Rust library for Android."
msgstr ""
"`rust_library`를 사용하여 안드로이드용 새 러스트 라이브러리를 만듭니다."
#: src/android/build-rules/library.md:5
msgid "Here we declare a dependency on two libraries:"
msgstr "여기서 두 개의 라이브러리에 대한 의존성을 선언합니다:"
#: src/android/build-rules/library.md:7
msgid "`libgreeting`, which we define below,"
msgstr "아래에 정의한 `libgreeting`."
#: src/android/build-rules/library.md:8
msgid ""
"`libtextwrap`, which is a crate already vendored in [`external/rust/crates/`]"
"(https://cs.android.com/android/platform/superproject/+/master:external/rust/"
"crates/)."
msgstr ""
"[`external/rust/crates/`](https://cs.android.com/android/platform/"
"superproject/+/master:external/rust/crates/)에 존재하는 `libtextwrap`."
#: src/android/build-rules/library.md:15
msgid ""
"```javascript\n"
"rust_binary {\n"
" name: \"hello_rust_with_dep\",\n"
" crate_name: \"hello_rust_with_dep\",\n"
" srcs: [\"src/main.rs\"],\n"
" rustlibs: [\n"
" \"libgreetings\",\n"
" \"libtextwrap\",\n"
" ],\n"
" prefer_rlib: true,\n"
"}\n"
"\n"
"rust_library {\n"
" name: \"libgreetings\",\n"
" crate_name: \"greetings\",\n"
" srcs: [\"src/lib.rs\"],\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_binary {\n"
" name: \"hello_rust_with_dep\",\n"
" crate_name: \"hello_rust_with_dep\",\n"
" srcs: [\"src/main.rs\"],\n"
" rustlibs: [\n"
" \"libgreetings\",\n"
" \"libtextwrap\",\n"
" ],\n"
" prefer_rlib: true,\n"
"}\n"
"\n"
"rust_library {\n"
" name: \"libgreetings\",\n"
" crate_name: \"greetings\",\n"
" srcs: [\"src/lib.rs\"],\n"
"}\n"
"```"
#: src/android/build-rules/library.md:36
msgid ""
"```rust,ignore\n"
"//! Rust demo.\n"
"\n"
"use greetings::greeting;\n"
"use textwrap::fill;\n"
"\n"
"/// Prints a greeting to standard output.\n"
"fn main() {\n"
" println!(\"{}\", fill(&greeting(\"Bob\"), 24));\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"//! Rust 데모입니다.\n"
"\n"
"use greetings::greeting;\n"
"use textwrap::fill;\n"
"\n"
"/// 인사말을 표준 출력으로 인쇄합니다.\n"
"fn main() {\n"
" println!(\"{}\", fill(&greeting(\"Bob\"), 24));\n"
"}\n"
"```"
#: src/android/build-rules/library.md:48
msgid "_hello_rust/src/lib.rs_:"
msgstr "_hello_rust/src/lib.rs_:"
#: src/android/build-rules/library.md:50
msgid ""
"```rust,ignore\n"
"//! Greeting library.\n"
"\n"
"/// Greet `name`.\n"
"pub fn greeting(name: &str) -> String {\n"
" format!(\"Hello {name}, it is very nice to meet you!\")\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"//! 인사말 라이브러리입니다.\n"
"\n"
"/// `이름`에게 인사합니다.\n"
"pub fn greeting(name: &str) -> String {\n"
" format!(\"Hello {name}, it is very nice to meet you!\")\n"
"}\n"
"```"
#: src/android/build-rules/library.md:59
msgid "You build, push, and run the binary like before:"
msgstr "이전처럼, 빌드하고, 가상 디바이스로 넣고, 실행합니다:"
#: src/android/build-rules/library.md:61
#, fuzzy
msgid ""
"```shell\n"
"m hello_rust_with_dep\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/hello_rust_with_dep /data/local/"
"tmp\"\n"
"adb shell /data/local/tmp/hello_rust_with_dep\n"
"```"
msgstr ""
"```shell\n"
"$ m hello_rust_with_dep\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/hello_rust_with_dep /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/hello_rust_with_dep\n"
"Hello Bob, it is very\n"
"nice to meet you!\n"
"```"
#: src/android/build-rules/library.md:67
msgid ""
"```text\n"
"Hello Bob, it is very\n"
"nice to meet you!\n"
"```"
msgstr ""
#: src/android/aidl.md:3
msgid ""
"The [Android Interface Definition Language (AIDL)](https://developer.android."
"com/guide/components/aidl) is supported in Rust:"
msgstr ""
"러스트는 [안드로이드 인터페이스 정의 언어(AIDL)](https://developer.android."
"com/guide/components/aidl)를 지원합니다:"
#: src/android/aidl.md:6
msgid "Rust code can call existing AIDL servers,"
msgstr "러스트 코드에서 기존 AIDL 서버를 호출 할 수 있습니다. "
#: src/android/aidl.md:7
msgid "You can create new AIDL servers in Rust."
msgstr "러스트에서 새로운 AIDL 서버를 생성할 수 있습니다."
#: src/android/aidl/interface.md:1
msgid "AIDL Interfaces"
msgstr "AIDL 인터페이스"
#: src/android/aidl/interface.md:3
msgid "You declare the API of your service using an AIDL interface:"
msgstr "AIDL 인터페이스를 이용해서 서비스의 API를 선언합니다:"
#: src/android/aidl/interface.md:5
msgid ""
"_birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl_:"
msgstr ""
"_birthday_service/aidl/com/example/birthdayservice/IBirthdayService.aidl_:"
#: src/android/aidl/interface.md:7
msgid ""
"```java\n"
"package com.example.birthdayservice;\n"
"\n"
"/** Birthday service interface. */\n"
"interface IBirthdayService {\n"
" /** Generate a Happy Birthday message. */\n"
" String wishHappyBirthday(String name, int years);\n"
"}\n"
"```"
msgstr ""
"```java\n"
"package com.example.birthdayservice;\n"
"\n"
"/** 생일 서비스 인터페이스입니다. */\n"
"interface IBirthdayService {\n"
" /** Generate a Happy Birthday message. */\n"
" String wishHappyBirthday(String name, int years);\n"
"}\n"
"```"
#: src/android/aidl/interface.md:17
msgid "_birthday_service/aidl/Android.bp_:"
msgstr "_birthday_service/aidl/Android.bp_:"
#: src/android/aidl/interface.md:19
msgid ""
"```javascript\n"
"aidl_interface {\n"
" name: \"com.example.birthdayservice\",\n"
" srcs: [\"com/example/birthdayservice/*.aidl\"],\n"
" unstable: true,\n"
" backend: {\n"
" rust: { // Rust is not enabled by default\n"
" enabled: true,\n"
" },\n"
" },\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"aidl_interface {\n"
" name: \"com.example.birthdayservice\",\n"
" srcs: [\"com/example/birthdayservice/*.aidl\"],\n"
" unstable: true,\n"
" backend: {\n"
" rust: { // Rust is not enabled by default\n"
" enabled: true,\n"
" },\n"
" },\n"
"}\n"
"```"
#: src/android/aidl/interface.md:32
msgid ""
"Add `vendor_available: true` if your AIDL file is used by a binary in the "
"vendor partition."
msgstr ""
"AIDL 파일이 벤더 파티션에 있는 바이너리에서 사용될 경우 `vendor_available: "
"true`를 추가합니다."
#: src/android/aidl/implementation.md:1
msgid "Service Implementation"
msgstr "서비스 구현"
#: src/android/aidl/implementation.md:3
msgid "We can now implement the AIDL service:"
msgstr "이제 AIDL서비스를 구현할 수 있습니다:"
#: src/android/aidl/implementation.md:5
msgid "_birthday_service/src/lib.rs_:"
msgstr "_birthday_service/src/lib.rs_:"
#: src/android/aidl/implementation.md:7
msgid ""
"```rust,ignore\n"
"//! Implementation of the `IBirthdayService` AIDL interface.\n"
"use com_example_birthdayservice::aidl::com::example::birthdayservice::"
"IBirthdayService::IBirthdayService;\n"
"use com_example_birthdayservice::binder;\n"
"\n"
"/// The `IBirthdayService` implementation.\n"
"pub struct BirthdayService;\n"
"\n"
"impl binder::Interface for BirthdayService {}\n"
"\n"
"impl IBirthdayService for BirthdayService {\n"
" fn wishHappyBirthday(&self, name: &str, years: i32) -> binder::"
"Result<String> {\n"
" Ok(format!(\n"
" \"Happy Birthday {name}, congratulations with the {years} years!"
"\"\n"
" ))\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"//! `IBirthdayService` AIDL 인터페이스의 구현입니다.\n"
"use com_example_birthdayservice::aidl::com::example::birthdayservice::"
"IBirthdayService::IBirthdayService;\n"
"use com_example_birthdayservice::binder;\n"
"\n"
"/// `IBirthdayService` 구현입니다.\n"
"pub struct BirthdayService;\n"
"\n"
"impl binder::Interface for BirthdayService {}\n"
"\n"
"impl IBirthdayService for BirthdayService {\n"
" fn wishHappyBirthday(&self, name: &str, years: i32) -> binder::"
"Result<String> {\n"
" Ok(format!(\n"
" \"Happy Birthday {name}, congratulations with the {years} years!"
"\"\n"
" ))\n"
" }\n"
"}\n"
"```"
#: src/android/aidl/implementation.md:26 src/android/aidl/server.md:28
#: src/android/aidl/client.md:37
msgid "_birthday_service/Android.bp_:"
msgstr "_birthday_service/Android.bp_:"
#: src/android/aidl/implementation.md:28
msgid ""
"```javascript\n"
"rust_library {\n"
" name: \"libbirthdayservice\",\n"
" srcs: [\"src/lib.rs\"],\n"
" crate_name: \"birthdayservice\",\n"
" rustlibs: [\n"
" \"com.example.birthdayservice-rust\",\n"
" \"libbinder_rs\",\n"
" ],\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_library {\n"
" name: \"libbirthdayservice\",\n"
" srcs: [\"src/lib.rs\"],\n"
" crate_name: \"birthdayservice\",\n"
" rustlibs: [\n"
" \"com.example.birthdayservice-rust\",\n"
" \"libbinder_rs\",\n"
" ],\n"
"}\n"
"```"
#: src/android/aidl/server.md:1
msgid "AIDL Server"
msgstr "AIDL 서버"
#: src/android/aidl/server.md:3
msgid "Finally, we can create a server which exposes the service:"
msgstr "마지막으로 서비스를 제공하는 서버를 만들 수 있습니다:"
#: src/android/aidl/server.md:5
msgid "_birthday_service/src/server.rs_:"
msgstr "_birthday_service/src/server.rs_:"
#: src/android/aidl/server.md:7
msgid ""
"```rust,ignore\n"
"//! Birthday service.\n"
"use birthdayservice::BirthdayService;\n"
"use com_example_birthdayservice::aidl::com::example::birthdayservice::"
"IBirthdayService::BnBirthdayService;\n"
"use com_example_birthdayservice::binder;\n"
"\n"
"const SERVICE_IDENTIFIER: &str = \"birthdayservice\";\n"
"\n"
"/// Entry point for birthday service.\n"
"fn main() {\n"
" let birthday_service = BirthdayService;\n"
" let birthday_service_binder = BnBirthdayService::new_binder(\n"
" birthday_service,\n"
" binder::BinderFeatures::default(),\n"
" );\n"
" binder::add_service(SERVICE_IDENTIFIER, birthday_service_binder."
"as_binder())\n"
" .expect(\"Failed to register service\");\n"
" binder::ProcessState::join_thread_pool()\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"//! 생일 서비스입니다.\n"
"use birthdayservice::BirthdayService;\n"
"use com_example_birthdayservice::aidl::com::example::birthdayservice::"
"IBirthdayService::BnBirthdayService;\n"
"use com_example_birthdayservice::binder;\n"
"\n"
"const SERVICE_IDENTIFIER: &str = \"birthdayservice\";\n"
"\n"
"/// 생일 서비스의 진입점입니다.\n"
"fn main() {\n"
" let birthday_service = BirthdayService;\n"
" let birthday_service_binder = BnBirthdayService::new_binder(\n"
" birthday_service,\n"
" binder::BinderFeatures::default(),\n"
" );\n"
" binder::add_service(SERVICE_IDENTIFIER, birthday_service_binder."
"as_binder())\n"
" .expect(\"Failed to register service\");\n"
" binder::ProcessState::join_thread_pool()\n"
"}\n"
"```"
#: src/android/aidl/server.md:30
msgid ""
"```javascript\n"
"rust_binary {\n"
" name: \"birthday_server\",\n"
" crate_name: \"birthday_server\",\n"
" srcs: [\"src/server.rs\"],\n"
" rustlibs: [\n"
" \"com.example.birthdayservice-rust\",\n"
" \"libbinder_rs\",\n"
" \"libbirthdayservice\",\n"
" ],\n"
" prefer_rlib: true,\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_binary {\n"
" name: \"birthday_server\",\n"
" crate_name: \"birthday_server\",\n"
" srcs: [\"src/server.rs\"],\n"
" rustlibs: [\n"
" \"com.example.birthdayservice-rust\",\n"
" \"libbinder_rs\",\n"
" \"libbirthdayservice\",\n"
" ],\n"
" prefer_rlib: true,\n"
"}\n"
"```"
#: src/android/aidl/deploy.md:3
msgid "We can now build, push, and start the service:"
msgstr "서비스를 빌드하고, 가상 디바이스에 넣고, 시작 할 수 있습니다:"
#: src/android/aidl/deploy.md:5
#, fuzzy
msgid ""
"```shell\n"
"m birthday_server\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/birthday_server /data/local/"
"tmp\"\n"
"adb shell /data/local/tmp/birthday_server\n"
"```"
msgstr ""
"```shell\n"
"$ m birthday_server\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/birthday_server /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/birthday_server\n"
"```"
#: src/android/aidl/deploy.md:11
msgid "In another terminal, check that the service runs:"
msgstr "다른 터미널을 띄워서 서비스가 잘 수행되고 있는지 확인합니다:"
#: src/android/aidl/deploy.md:13
#, fuzzy
msgid ""
"```shell\n"
"adb shell service check birthdayservice\n"
"```"
msgstr ""
"```shell\n"
"$ adb shell service check birthdayservice\n"
"Service birthdayservice: found\n"
"```"
#: src/android/aidl/deploy.md:17
#, fuzzy
msgid ""
"```text\n"
"Service birthdayservice: found\n"
"```"
msgstr ""
"```shell\n"
"$ adb shell service check birthdayservice\n"
"Service birthdayservice: found\n"
"```"
#: src/android/aidl/deploy.md:21
msgid "You can also call the service with `service call`:"
msgstr "`service call`명렁어로 서비스를 호출할 수도 있습니다:"
#: src/android/aidl/deploy.md:23
#, fuzzy
msgid ""
"```shell\n"
"adb shell service call birthdayservice 1 s16 Bob i32 24\n"
"```"
msgstr ""
"```shell\n"
"$ adb shell service check birthdayservice\n"
"Service birthdayservice: found\n"
"```"
#: src/android/aidl/deploy.md:27
#, fuzzy
msgid ""
"```text\n"
"Result: Parcel(\n"
" 0x00000000: 00000000 00000036 00610048 00700070 '....6...H.a.p.p.'\n"
" 0x00000010: 00200079 00690042 00740072 00640068 'y. .B.i.r.t.h.d.'\n"
" 0x00000020: 00790061 00420020 0062006f 0020002c 'a.y. .B.o.b.,. .'\n"
" 0x00000030: 006f0063 0067006e 00610072 00750074 'c.o.n.g.r.a.t.u.'\n"
" 0x00000040: 0061006c 00690074 006e006f 00200073 'l.a.t.i.o.n.s. .'\n"
" 0x00000050: 00690077 00680074 00740020 00650068 'w.i.t.h. .t.h.e.'\n"
" 0x00000060: 00320020 00200034 00650079 00720061 ' .2.4. .y.e.a.r.'\n"
" 0x00000070: 00210073 00000000 's.!..... ')\n"
"```"
msgstr ""
"```shell\n"
"$ $ adb shell service call birthdayservice 1 s16 Bob i32 24\n"
"Result: Parcel(\n"
" 0x00000000: 00000000 00000036 00610048 00700070 '....6...H.a.p.p.'\n"
" 0x00000010: 00200079 00690042 00740072 00640068 'y. .B.i.r.t.h.d.'\n"
" 0x00000020: 00790061 00420020 0062006f 0020002c 'a.y. .B.o.b.,. .'\n"
" 0x00000030: 006f0063 0067006e 00610072 00750074 'c.o.n.g.r.a.t.u.'\n"
" 0x00000040: 0061006c 00690074 006e006f 00200073 'l.a.t.i.o.n.s. .'\n"
" 0x00000050: 00690077 00680074 00740020 00650068 'w.i.t.h. .t.h.e.'\n"
" 0x00000060: 00320020 00200034 00650079 00720061 ' .2.4. .y.e.a.r.'\n"
" 0x00000070: 00210073 00000000 's.!..... ')\n"
"```"
#: src/android/aidl/client.md:1
msgid "AIDL Client"
msgstr "AIDL 클라이언트"
#: src/android/aidl/client.md:3
msgid "Finally, we can create a Rust client for our new service."
msgstr ""
"마지막으로, 아까 추가한 서비스에 대한 클라이언트를 러스트로 만들겠습니다."
#: src/android/aidl/client.md:5
msgid "_birthday_service/src/client.rs_:"
msgstr "_birthday_service/src/client.rs_:"
#: src/android/aidl/client.md:7
msgid ""
"```rust,ignore\n"
"//! Birthday service.\n"
"use com_example_birthdayservice::aidl::com::example::birthdayservice::"
"IBirthdayService::IBirthdayService;\n"
"use com_example_birthdayservice::binder;\n"
"\n"
"const SERVICE_IDENTIFIER: &str = \"birthdayservice\";\n"
"\n"
"/// Connect to the BirthdayService.\n"
"pub fn connect() -> Result<binder::Strong<dyn IBirthdayService>, binder::"
"StatusCode> {\n"
" binder::get_interface(SERVICE_IDENTIFIER)\n"
"}\n"
"\n"
"/// Call the birthday service.\n"
"fn main() -> Result<(), binder::Status> {\n"
" let name = std::env::args()\n"
" .nth(1)\n"
" .unwrap_or_else(|| String::from(\"Bob\"));\n"
" let years = std::env::args()\n"
" .nth(2)\n"
" .and_then(|arg| arg.parse::<i32>().ok())\n"
" .unwrap_or(42);\n"
"\n"
" binder::ProcessState::start_thread_pool();\n"
" let service = connect().expect(\"Failed to connect to "
"BirthdayService\");\n"
" let msg = service.wishHappyBirthday(&name, years)?;\n"
" println!(\"{msg}\");\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"//! 생일 서비스입니다.\n"
"use com_example_birthdayservice::aidl::com::example::birthdayservice::"
"IBirthdayService::IBirthdayService;\n"
"use com_example_birthdayservice::binder;\n"
"\n"
"const SERVICE_IDENTIFIER: &str = \"birthdayservice\";\n"
"\n"
"/// BirthdayService에 연결합니다.\n"
"pub fn connect() -> Result<binder::Strong<dyn IBirthdayService>, binder::"
"StatusCode> {\n"
" binder::get_interface(SERVICE_IDENTIFIER)\n"
"}\n"
"\n"
"/// 생일 서비스를 호출합니다.\n"
"fn main() -> Result<(), binder::Status> {\n"
" let name = std::env::args()\n"
" .nth(1)\n"
" .unwrap_or_else(|| String::from(\"Bob\"));\n"
" let years = std::env::args()\n"
" .nth(2)\n"
" .and_then(|arg| arg.parse::<i32>().ok())\n"
" .unwrap_or(42);\n"
"\n"
" binder::ProcessState::start_thread_pool();\n"
" let service = connect().expect(\"Failed to connect to "
"BirthdayService\");\n"
" let msg = service.wishHappyBirthday(&name, years)?;\n"
" println!(\"{msg}\");\n"
" Ok(())\n"
"}\n"
"```"
#: src/android/aidl/client.md:39
msgid ""
"```javascript\n"
"rust_binary {\n"
" name: \"birthday_client\",\n"
" crate_name: \"birthday_client\",\n"
" srcs: [\"src/client.rs\"],\n"
" rustlibs: [\n"
" \"com.example.birthdayservice-rust\",\n"
" \"libbinder_rs\",\n"
" ],\n"
" prefer_rlib: true,\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_binary {\n"
" name: \"birthday_client\",\n"
" crate_name: \"birthday_client\",\n"
" srcs: [\"src/client.rs\"],\n"
" rustlibs: [\n"
" \"com.example.birthdayservice-rust\",\n"
" \"libbinder_rs\",\n"
" ],\n"
" prefer_rlib: true,\n"
"}\n"
"```"
#: src/android/aidl/client.md:52
msgid "Notice that the client does not depend on `libbirthdayservice`."
msgstr "클라이언트는 `libbirthdayservice`에 의존하지 않음에 주목하세요."
#: src/android/aidl/client.md:54
msgid "Build, push, and run the client on your device:"
msgstr "빌드하고, 가상 디바이스로 넣고, 실행합니다:"
#: src/android/aidl/client.md:56
#, fuzzy
msgid ""
"```shell\n"
"m birthday_client\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/birthday_client /data/local/"
"tmp\"\n"
"adb shell /data/local/tmp/birthday_client Charlie 60\n"
"```"
msgstr ""
"```shell\n"
"$ m birthday_server\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/birthday_server /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/birthday_server\n"
"```"
#: src/android/aidl/client.md:62
msgid ""
"```text\n"
"Happy Birthday Charlie, congratulations with the 60 years!\n"
"```"
msgstr ""
#: src/android/aidl/changing.md:3
msgid ""
"Let us extend the API with more functionality: we want to let clients "
"specify a list of lines for the birthday card:"
msgstr ""
"API를 확장하여 더 많은 기능을 제공해 봅시다. 클라이언트가 생일 카드에 담길 내"
"용을 지정할 수 있도록 하겠습니다:"
#: src/android/aidl/changing.md:6
msgid ""
"```java\n"
"package com.example.birthdayservice;\n"
"\n"
"/** Birthday service interface. */\n"
"interface IBirthdayService {\n"
" /** Generate a Happy Birthday message. */\n"
" String wishHappyBirthday(String name, int years, in String[] text);\n"
"}\n"
"```"
msgstr ""
"```java\n"
"package com.example.birthdayservice;\n"
"\n"
"/** 생일 서비스 인터페이스입니다. */\n"
"interface IBirthdayService {\n"
" /** Generate a Happy Birthday message. */\n"
" String wishHappyBirthday(String name, int years, in String[] text);\n"
"}\n"
"```"
#: src/android/logging.md:3
msgid ""
"You should use the `log` crate to automatically log to `logcat` (on-device) "
"or `stdout` (on-host):"
msgstr ""
"`log` 크레이트를 사용하면 안드로이드 디바이스 안에서 수행될 때에는 `logcat`으"
"로, 호스트에서 수행될 때에는 `stdout`으로 로그가 자동으로 출력이 되도록 할 "
"수 있습니다:"
#: src/android/logging.md:6
msgid "_hello_rust_logs/Android.bp_:"
msgstr "_hello_rust_logs/Android.bp_:"
#: src/android/logging.md:8
msgid ""
"```javascript\n"
"rust_binary {\n"
" name: \"hello_rust_logs\",\n"
" crate_name: \"hello_rust_logs\",\n"
" srcs: [\"src/main.rs\"],\n"
" rustlibs: [\n"
" \"liblog_rust\",\n"
" \"liblogger\",\n"
" ],\n"
" prefer_rlib: true,\n"
" host_supported: true,\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_binary {\n"
" name: \"hello_rust_logs\",\n"
" crate_name: \"hello_rust_logs\",\n"
" srcs: [\"src/main.rs\"],\n"
" rustlibs: [\n"
" \"liblog_rust\",\n"
" \"liblogger\",\n"
" ],\n"
" prefer_rlib: true,\n"
" host_supported: true,\n"
"}\n"
"```"
#: src/android/logging.md:22
msgid "_hello_rust_logs/src/main.rs_:"
msgstr "_hello_rust_logs/src/main.rs_:"
#: src/android/logging.md:24
msgid ""
"```rust,ignore\n"
"//! Rust logging demo.\n"
"\n"
"use log::{debug, error, info};\n"
"\n"
"/// Logs a greeting.\n"
"fn main() {\n"
" logger::init(\n"
" logger::Config::default()\n"
" .with_tag_on_device(\"rust\")\n"
" .with_min_level(log::Level::Trace),\n"
" );\n"
" debug!(\"Starting program.\");\n"
" info!(\"Things are going fine.\");\n"
" error!(\"Something went wrong!\");\n"
"}\n"
"```"
msgstr ""
"```rust,ignore\n"
"//! Rust 로깅 데모입니다.\n"
"\n"
"use log::{debug, error, info};\n"
"\n"
"/// 인사말을 기록합니다.\n"
"fn main() {\n"
" logger::init(\n"
" logger::Config::default()\n"
" .with_tag_on_device(\"rust\")\n"
" .with_min_level(log::Level::Trace),\n"
" );\n"
" debug!(\"Starting program.\");\n"
" info!(\"Things are going fine.\");\n"
" error!(\"Something went wrong!\");\n"
"}\n"
"```"
#: src/android/logging.md:42 src/android/interoperability/with-c/bindgen.md:98
#: src/android/interoperability/with-c/rust.md:73
msgid "Build, push, and run the binary on your device:"
msgstr "빌드하고, 가상 디바이스에 넣고, 실행합니다:"
#: src/android/logging.md:44
#, fuzzy
msgid ""
"```shell\n"
"m hello_rust_logs\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/hello_rust_logs /data/local/"
"tmp\"\n"
"adb shell /data/local/tmp/hello_rust_logs\n"
"```"
msgstr ""
"```shell\n"
"$ m hello_rust_logs\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/hello_rust_logs /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/hello_rust_logs\n"
"```"
#: src/android/logging.md:50
msgid "The logs show up in `adb logcat`:"
msgstr "`adb logcat`커맨드로 로그를 확인합니다:"
#: src/android/logging.md:52
#, fuzzy
msgid ""
"```shell\n"
"adb logcat -s rust\n"
"```"
msgstr ""
"```shell\n"
"$ sudo apt install cargo rust-src rustfmt\n"
"```"
#: src/android/logging.md:56
#, fuzzy
msgid ""
"```text\n"
"09-08 08:38:32.454 2420 2420 D rust: hello_rust_logs: Starting program.\n"
"09-08 08:38:32.454 2420 2420 I rust: hello_rust_logs: Things are going "
"fine.\n"
"09-08 08:38:32.454 2420 2420 E rust: hello_rust_logs: Something went "
"wrong!\n"
"```"
msgstr ""
"```shell\n"
"$ adb logcat -s rust\n"
"09-08 08:38:32.454 2420 2420 D rust: hello_rust_logs: Starting program.\n"
"09-08 08:38:32.454 2420 2420 I rust: hello_rust_logs: Things are going "
"fine.\n"
"09-08 08:38:32.454 2420 2420 E rust: hello_rust_logs: Something went "
"wrong!\n"
"```"
#: src/android/interoperability.md:3
msgid ""
"Rust has excellent support for interoperability with other languages. This "
"means that you can:"
msgstr "러스트는 다음과 같이 다른 언어와의 상호운용성을 훌륭히 지원합니다:"
#: src/android/interoperability.md:6
msgid "Call Rust functions from other languages."
msgstr "타 언어에서 러스트 함수를 호출합니다."
#: src/android/interoperability.md:7
msgid "Call functions written in other languages from Rust."
msgstr "타 언어의 함수를 러스트에서 호출합니다."
#: src/android/interoperability.md:9
msgid ""
"When you call functions in a foreign language we say that you're using a "
"_foreign function interface_, also known as FFI."
msgstr ""
"타 언어의 함수를 호출해서 사용하는 것을 FFI(foreign function interface)라고 "
"합니다."
#: src/android/interoperability/with-c.md:1
msgid "Interoperability with C"
msgstr "C와의 상호운용성"
#: src/android/interoperability/with-c.md:3
msgid ""
"Rust has full support for linking object files with a C calling convention. "
"Similarly, you can export Rust functions and call them from C."
msgstr ""
"러스트는 C 호출규약을 따르는 오브젝트 파일과 링킹할 수 있습니다. 또한, 반대"
"로 러스트 함수를 내보내서 C에서 호출 할 수 도 있습니다."
#: src/android/interoperability/with-c.md:6
msgid "You can do it by hand if you want:"
msgstr "원한다면 아래와 같이 수동으로 코딩할 수 있습니다:"
#: src/android/interoperability/with-c.md:8
msgid ""
"```rust\n"
"extern \"C\" {\n"
" fn abs(x: i32) -> i32;\n"
"}\n"
"\n"
"fn main() {\n"
" let x = -42;\n"
" let abs_x = unsafe { abs(x) };\n"
" println!(\"{x}, {abs_x}\");\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"extern \"C\" {\n"
" fn abs(x: i32) -> i32;\n"
"}\n"
"\n"
"fn main() {\n"
" let x = -42;\n"
" let abs_x = unsafe { abs(x) };\n"
" println!(\"{x}, {abs_x}\");\n"
"}\n"
"```"
#: src/android/interoperability/with-c.md:20
msgid ""
"We already saw this in the [Safe FFI Wrapper exercise](../../exercises/day-3/"
"safe-ffi-wrapper.md)."
msgstr ""
"우리는 이미 [Safe FFI 래퍼 연습문제](../../exercises/day-3/safe-ffi-wrapper."
"md)에서 이를 다루었습니다."
#: src/android/interoperability/with-c.md:23
msgid ""
"This assumes full knowledge of the target platform. Not recommended for "
"production."
msgstr ""
"이러한 방법은 타겟 플랫폼의 모든 부분을 사전에 알고 있다는 전제를 깔고 있습니"
"다. 상용 프로젝트에서는 권장하지 않습니다."
#: src/android/interoperability/with-c.md:26
msgid "We will look at better options next."
msgstr "좀 더 나은 옵션을 살펴보겠습니다."
#: src/android/interoperability/with-c/bindgen.md:1
msgid "Using Bindgen"
msgstr "Bindgen 사용하기"
#: src/android/interoperability/with-c/bindgen.md:3
msgid ""
"The [bindgen](https://rust-lang.github.io/rust-bindgen/introduction.html) "
"tool can auto-generate bindings from a C header file."
msgstr ""
"[bindgen](https://rust-lang.github.io/rust-bindgen/introduction.html)는 C 헤"
"더파일에서 러스트 바인딩을 자동으로 생성하는 도구입니다."
#: src/android/interoperability/with-c/bindgen.md:6
msgid "First create a small C library:"
msgstr "먼저 작은 C라이브러리를 만들어 보겠습니다:"
#: src/android/interoperability/with-c/bindgen.md:8
msgid "_interoperability/bindgen/libbirthday.h_:"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:10
msgid ""
"```c\n"
"typedef struct card {\n"
" const char* name;\n"
" int years;\n"
"} card;\n"
"\n"
"void print_card(const card* card);\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:19
msgid "_interoperability/bindgen/libbirthday.c_:"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:21
msgid ""
"```c\n"
"#include <stdio.h>\n"
"#include \"libbirthday.h\"\n"
"\n"
"void print_card(const card* card) {\n"
" printf(\"+--------------\\n\");\n"
" printf(\"| Happy Birthday %s!\\n\", card->name);\n"
" printf(\"| Congratulations with the %i years!\\n\", card->years);\n"
" printf(\"+--------------\\n\");\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:33
msgid "Add this to your `Android.bp` file:"
msgstr "`Android.bp` 파일에 아래를 추가합니다:"
#: src/android/interoperability/with-c/bindgen.md:35
#: src/android/interoperability/with-c/bindgen.md:55
#: src/android/interoperability/with-c/bindgen.md:69
#: src/android/interoperability/with-c/bindgen.md:108
msgid "_interoperability/bindgen/Android.bp_:"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:37
msgid ""
"```javascript\n"
"cc_library {\n"
" name: \"libbirthday\",\n"
" srcs: [\"libbirthday.c\"],\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:44
msgid ""
"Create a wrapper header file for the library (not strictly needed in this "
"example):"
msgstr ""
"라이브러리에 대한 헤더 파일을 만듭니다(이 예시에서는 반드시 필요한 것은 아닙"
"니다.):"
#: src/android/interoperability/with-c/bindgen.md:47
msgid "_interoperability/bindgen/libbirthday_wrapper.h_:"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:49
msgid ""
"```c\n"
"#include \"libbirthday.h\"\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:53
msgid "You can now auto-generate the bindings:"
msgstr "이제 바인딩을 자동으로 생성할 수 있습니다:"
#: src/android/interoperability/with-c/bindgen.md:57
msgid ""
"```javascript\n"
"rust_bindgen {\n"
" name: \"libbirthday_bindgen\",\n"
" crate_name: \"birthday_bindgen\",\n"
" wrapper_src: \"libbirthday_wrapper.h\",\n"
" source_stem: \"bindings\",\n"
" static_libs: [\"libbirthday\"],\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:67
msgid "Finally, we can use the bindings in our Rust program:"
msgstr "마침내, 러스트 프로그램에서 바인딩을 사용할 수 있습니다:"
#: src/android/interoperability/with-c/bindgen.md:71
msgid ""
"```javascript\n"
"rust_binary {\n"
" name: \"print_birthday_card\",\n"
" srcs: [\"main.rs\"],\n"
" rustlibs: [\"libbirthday_bindgen\"],\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:79
msgid "_interoperability/bindgen/main.rs_:"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:81
msgid ""
"```rust,compile_fail\n"
"//! Bindgen demo.\n"
"\n"
"use birthday_bindgen::{card, print_card};\n"
"\n"
"fn main() {\n"
" let name = std::ffi::CString::new(\"Peter\").unwrap();\n"
" let card = card {\n"
" name: name.as_ptr(),\n"
" years: 42,\n"
" };\n"
" unsafe {\n"
" print_card(&card as *const card);\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:100
#, fuzzy
msgid ""
"```shell\n"
"m print_birthday_card\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/print_birthday_card /data/local/"
"tmp\"\n"
"adb shell /data/local/tmp/print_birthday_card\n"
"```"
msgstr ""
"```shell\n"
"$ m birthday_server\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/birthday_server /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/birthday_server\n"
"```"
#: src/android/interoperability/with-c/bindgen.md:106
msgid "Finally, we can run auto-generated tests to ensure the bindings work:"
msgstr ""
"마지막으로, 바인딩이 잘 작동하는지 확인하기 위해, 자동 생성된 테스트를 실행"
"해 보겠습니다:"
#: src/android/interoperability/with-c/bindgen.md:110
msgid ""
"```javascript\n"
"rust_test {\n"
" name: \"libbirthday_bindgen_test\",\n"
" srcs: [\":libbirthday_bindgen\"],\n"
" crate_name: \"libbirthday_bindgen_test\",\n"
" test_suites: [\"general-tests\"],\n"
" auto_gen_config: true,\n"
" clippy_lints: \"none\", // Generated file, skip linting\n"
" lints: \"none\",\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/bindgen.md:122
msgid ""
"```shell\n"
"atest libbirthday_bindgen_test\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/rust.md:1
msgid "Calling Rust"
msgstr "C에서 러스트 호출"
#: src/android/interoperability/with-c/rust.md:3
msgid "Exporting Rust functions and types to C is easy:"
msgstr "러스트에서 타입과 함수를 C로 내보내는 것은 간단합니다:"
#: src/android/interoperability/with-c/rust.md:5
msgid "_interoperability/rust/libanalyze/analyze.rs_"
msgstr ""
#: src/android/interoperability/with-c/rust.md:7
msgid ""
"```rust,editable\n"
"//! Rust FFI demo.\n"
"#![deny(improper_ctypes_definitions)]\n"
"\n"
"use std::os::raw::c_int;\n"
"\n"
"/// Analyze the numbers.\n"
"#[no_mangle]\n"
"pub extern \"C\" fn analyze_numbers(x: c_int, y: c_int) {\n"
" if x < y {\n"
" println!(\"x ({x}) is smallest!\");\n"
" } else {\n"
" println!(\"y ({y}) is probably larger than x ({x})\");\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/rust.md:24
msgid "_interoperability/rust/libanalyze/analyze.h_"
msgstr ""
#: src/android/interoperability/with-c/rust.md:26
msgid ""
"```c\n"
"#ifndef ANALYSE_H\n"
"#define ANALYSE_H\n"
"\n"
"extern \"C\" {\n"
"void analyze_numbers(int x, int y);\n"
"}\n"
"\n"
"#endif\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/rust.md:37
msgid "_interoperability/rust/libanalyze/Android.bp_"
msgstr ""
#: src/android/interoperability/with-c/rust.md:39
msgid ""
"```javascript\n"
"rust_ffi {\n"
" name: \"libanalyze_ffi\",\n"
" crate_name: \"analyze_ffi\",\n"
" srcs: [\"analyze.rs\"],\n"
" include_dirs: [\".\"],\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/rust.md:48
msgid "We can now call this from a C binary:"
msgstr "이제 이 러스트 함수를 C바이너리에서 호출할 수 있습니다:"
#: src/android/interoperability/with-c/rust.md:50
msgid "_interoperability/rust/analyze/main.c_"
msgstr ""
#: src/android/interoperability/with-c/rust.md:52
msgid ""
"```c\n"
"#include \"analyze.h\"\n"
"\n"
"int main() {\n"
" analyze_numbers(10, 20);\n"
" analyze_numbers(123, 123);\n"
" return 0;\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/rust.md:62
msgid "_interoperability/rust/analyze/Android.bp_"
msgstr ""
#: src/android/interoperability/with-c/rust.md:64
msgid ""
"```javascript\n"
"cc_binary {\n"
" name: \"analyze_numbers\",\n"
" srcs: [\"main.c\"],\n"
" static_libs: [\"libanalyze_ffi\"],\n"
"}\n"
"```"
msgstr ""
#: src/android/interoperability/with-c/rust.md:75
#, fuzzy
msgid ""
"```shell\n"
"m analyze_numbers\n"
"adb push \"$ANDROID_PRODUCT_OUT/system/bin/analyze_numbers /data/local/"
"tmp\"\n"
"adb shell /data/local/tmp/analyze_numbers\n"
"```"
msgstr ""
"```shell\n"
"$ m birthday_server\n"
"$ adb push \"$ANDROID_PRODUCT_OUT/system/bin/birthday_server /data/local/"
"tmp\"\n"
"$ adb shell /data/local/tmp/birthday_server\n"
"```"
#: src/android/interoperability/with-c/rust.md:83
msgid ""
"`#[no_mangle]` disables Rust's usual name mangling, so the exported symbol "
"will just be the name of the function. You can also use `#[export_name = "
"\"some_name\"]` to specify whatever name you want."
msgstr ""
"`#[no_mangle]`은 러스트의 네임 맹글링(name mangling)을 비활성화하므로 외부로 "
"노출되는 심볼의 이름은 함수의 이름 그대로가 됩니다. 심볼 이름을 바꾸고 싶다"
"면 `#[export_name = \"some_name\"]`을 사용합니다."
#: src/android/interoperability/cpp.md:3
msgid ""
"The [CXX crate](https://cxx.rs/) makes it possible to do safe "
"interoperability between Rust and C++."
msgstr ""
"[CXX 크레이트](https://cxx.rs/)는 러스트와 C++ 사이의 안전한 상호운용성을 가"
"능하게 해줍니다."
#: src/android/interoperability/cpp.md:6
msgid "The overall approach looks like this:"
msgstr "전체적인 접근 방법은 다음과 같습니다:"
#: src/android/interoperability/cpp.md:10
msgid ""
"See the [CXX tutorial](https://cxx.rs/tutorial.html) for an full example of "
"using this."
msgstr ""
"사용하는 방법에 대해서는[CXX 튜토리얼](https://cxx.rs/tutorial.html) 를 참조"
"합니다."
#: src/android/interoperability/cpp.md:14
msgid ""
"At this point, the instructor should switch to the [CXX tutorial](https://"
"cxx.rs/tutorial.html)."
msgstr ""
#: src/android/interoperability/cpp.md:16
msgid "Walk the students through the tutorial step by step."
msgstr ""
#: src/android/interoperability/cpp.md:18
msgid ""
"Highlight how CXX presents a clean interface without unsafe code in _both "
"languages_."
msgstr ""
#: src/android/interoperability/cpp.md:20
msgid ""
"Show the correspondence between [Rust and C++ types](https://cxx.rs/bindings."
"html):"
msgstr ""
#: src/android/interoperability/cpp.md:22
msgid ""
"Explain how a Rust `String` cannot map to a C++ `std::string` (the latter "
"does not uphold the UTF-8 invariant). Show that despite being different "
"types, `rust::String` in C++ can be easily constructed from a C++ `std::"
"string`, making it very ergonomic to use."
msgstr ""
#: src/android/interoperability/cpp.md:28
msgid ""
"Explain that a Rust function returning `Result<T, E>` becomes a function "
"which throws a `E` exception in C++ (and vice versa)."
msgstr ""
#: src/android/interoperability/java.md:1
msgid "Interoperability with Java"
msgstr "Java와의 상호운용성"
#: src/android/interoperability/java.md:3
msgid ""
"Java can load shared objects via [Java Native Interface (JNI)](https://en."
"wikipedia.org/wiki/Java_Native_Interface). The [`jni` crate](https://docs.rs/"
"jni/) allows you to create a compatible library."
msgstr ""
"자바는 [Java Native Interface(JNI)](https://en.wikipedia.org/wiki/"
"Java_Native_Interface)를 통해 공유 라이브러리를 로드할 수 있습니다. [`jni` 크"
"레이트](https://docs.rs/jni/)를 사용하여 JNI 라이브러리를 만들 수 있습니다."
#: src/android/interoperability/java.md:7
msgid "First, we create a Rust function to export to Java:"
msgstr "먼저, 자바로 내보낼 러스트 함수를 생성합니다:"
#: src/android/interoperability/java.md:9
msgid "_interoperability/java/src/lib.rs_:"
msgstr "_interoperability/java/src/lib.rs_:"
#: src/android/interoperability/java.md:11
msgid ""
"```rust,compile_fail\n"
"//! Rust <-> Java FFI demo.\n"
"\n"
"use jni::objects::{JClass, JString};\n"
"use jni::sys::jstring;\n"
"use jni::JNIEnv;\n"
"\n"
"/// HelloWorld::hello method implementation.\n"
"#[no_mangle]\n"
"pub extern \"system\" fn Java_HelloWorld_hello(\n"
" env: JNIEnv,\n"
" _class: JClass,\n"
" name: JString,\n"
") -> jstring {\n"
" let input: String = env.get_string(name).unwrap().into();\n"
" let greeting = format!(\"Hello, {input}!\");\n"
" let output = env.new_string(greeting).unwrap();\n"
" output.into_inner()\n"
"}\n"
"```"
msgstr ""
"```rust,compile_fail\n"
"//! Rust <-> Java FFI 데모입니다.\n"
"\n"
"use jni::objects::{JClass, JString};\n"
"use jni::sys::jstring;\n"
"use jni::JNIEnv;\n"
"\n"
"/// HelloWorld::hello 메서드 구현입니다.\n"
"#[no_mangle]\n"
"pub extern \"system\" fn Java_HelloWorld_hello(\n"
" env: JNIEnv,\n"
" _class: JClass,\n"
" name: JString,\n"
") -> jstring {\n"
" let input: String = env.get_string(name).unwrap().into();\n"
" let greeting = format!(\"Hello, {input}!\");\n"
" let output = env.new_string(greeting).unwrap();\n"
" output.into_inner()\n"
"}\n"
"```"
#: src/android/interoperability/java.md:32
#: src/android/interoperability/java.md:62
msgid "_interoperability/java/Android.bp_:"
msgstr "_interoperability/java/Android.bp_:"
#: src/android/interoperability/java.md:34
msgid ""
"```javascript\n"
"rust_ffi_shared {\n"
" name: \"libhello_jni\",\n"
" crate_name: \"hello_jni\",\n"
" srcs: [\"src/lib.rs\"],\n"
" rustlibs: [\"libjni\"],\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"rust_ffi_shared {\n"
" name: \"libhello_jni\",\n"
" crate_name: \"hello_jni\",\n"
" srcs: [\"src/lib.rs\"],\n"
" rustlibs: [\"libjni\"],\n"
"}\n"
"```"
#: src/android/interoperability/java.md:43
msgid "Finally, we can call this function from Java:"
msgstr "자바에서 이 함수를 호출 할 수 있습니다:"
#: src/android/interoperability/java.md:45
msgid "_interoperability/java/HelloWorld.java_:"
msgstr "_interoperability/java/HelloWorld.java_:"
#: src/android/interoperability/java.md:47
msgid ""
"```java\n"
"class HelloWorld {\n"
" private static native String hello(String name);\n"
"\n"
" static {\n"
" System.loadLibrary(\"hello_jni\");\n"
" }\n"
"\n"
" public static void main(String[] args) {\n"
" String output = HelloWorld.hello(\"Alice\");\n"
" System.out.println(output);\n"
" }\n"
"}\n"
"```"
msgstr ""
"```java\n"
"class HelloWorld {\n"
" private static native String hello(String name);\n"
"\n"
" static {\n"
" System.loadLibrary(\"hello_jni\");\n"
" }\n"
"\n"
" public static void main(String[] args) {\n"
" String output = HelloWorld.hello(\"Alice\");\n"
" System.out.println(output);\n"
" }\n"
"}\n"
"```"
#: src/android/interoperability/java.md:64
msgid ""
"```javascript\n"
"java_binary {\n"
" name: \"helloworld_jni\",\n"
" srcs: [\"HelloWorld.java\"],\n"
" main_class: \"HelloWorld\",\n"
" required: [\"libhello_jni\"],\n"
"}\n"
"```"
msgstr ""
"```javascript\n"
"java_binary {\n"
" name: \"helloworld_jni\",\n"
" srcs: [\"HelloWorld.java\"],\n"
" main_class: \"HelloWorld\",\n"
" required: [\"libhello_jni\"],\n"
"}\n"
"```"
#: src/android/interoperability/java.md:73
msgid "Finally, you can build, sync, and run the binary:"
msgstr "마지막으로 바이너리를 빌드, 싱크, 실행합니다:"
#: src/android/interoperability/java.md:75
#, fuzzy
msgid ""
"```shell\n"
"m helloworld_jni\n"
"adb sync # requires adb root && adb remount\n"
"adb shell /system/bin/helloworld_jni\n"
"```"
msgstr ""
"```shell\n"
"$ m helloworld_jni\n"
"$ adb sync # requires adb root && adb remount\n"
"$ adb shell /system/bin/helloworld_jni\n"
"```"
#: src/exercises/android/morning.md:3
#, fuzzy
msgid ""
"This is a group exercise: We will look at one of the projects you work with "
"and try to integrate some Rust into it. Some suggestions:"
msgstr ""
"마지막 연습문제는 여러분이 작업하고 있는 프로젝트 중 하나를 FFI로 러스트와 연"
"계 해보는 것입니다. 몇 가지 예시입니다:"
#: src/exercises/android/morning.md:6
msgid "Call your AIDL service with a client written in Rust."
msgstr "당신의 AIDL서비스를 러스트 클라이언트에서 호출해봅니다."
#: src/exercises/android/morning.md:8
msgid "Move a function from your project to Rust and call it."
msgstr "당신의 프로젝트의 함수를 러스트로 옮기고 호출해봅니다."
#: src/exercises/android/morning.md:12
msgid ""
"No solution is provided here since this is open-ended: it relies on someone "
"in the class having a piece of code which you can turn in to Rust on the fly."
msgstr ""
"이 연습문제는 열려있기 때문에 해답이 제공되지 않습니다. 클래스에서 제출된 코"
"드에 의존합니다."
#: src/bare-metal.md:1
#, fuzzy
msgid "Welcome to Bare Metal Rust"
msgstr "Welcome to Comprehensive Rust 🦀"
#: src/bare-metal.md:3
msgid ""
"This is a standalone one-day course about bare-metal Rust, aimed at people "
"who are familiar with the basics of Rust (perhaps from completing the "
"Comprehensive Rust course), and ideally also have some experience with bare-"
"metal programming in some other language such as C."
msgstr ""
"이 과정은 Rust에 대해 어느정도 경험이 있고 (아마도 Comprehensive Rust 과정을 "
"통해) C와 같은 다른 언어로 bare-metal 프로그래밍을 해 본 사용자를 대상으로 하"
"는 bare-metal Rust에 관한 독립적인 1일 과정입니다."
#: src/bare-metal.md:7
msgid ""
"Today we will talk about 'bare-metal' Rust: running Rust code without an OS "
"underneath us. This will be divided into several parts:"
msgstr ""
"오늘은 OS를 사용하지 않고 Rust 코드를 실행하는 'bare-metal' Rust에 관해 알아"
"봅니다. 본 강의의 구성은 다음과 같습니다."
#: src/bare-metal.md:10
msgid "What is `no_std` Rust?"
msgstr "`no_std` Rust란 무엇인가요?"
#: src/bare-metal.md:11
msgid "Writing firmware for microcontrollers."
msgstr "마이크로컨트롤러용 펌웨어 작성"
#: src/bare-metal.md:12
msgid "Writing bootloader / kernel code for application processors."
msgstr "애플리케이션 프로세서를 위한 부트로더 / 커널 코드 작성"
#: src/bare-metal.md:13
msgid "Some useful crates for bare-metal Rust development."
msgstr "bare-metal Rust 개발을 위한 유용한 크레이트"
#: src/bare-metal.md:15
msgid ""
"For the microcontroller part of the course we will use the [BBC micro:bit]"
"(https://microbit.org/) v2 as an example. It's a [development board](https://"
"tech.microbit.org/hardware/) based on the Nordic nRF51822 microcontroller "
"with some LEDs and buttons, an I2C-connected accelerometer and compass, and "
"an on-board SWD debugger."
msgstr ""
"이 강의에서는 [BBC micro:bit](https://microbit.org/) v2마이크로컨트롤러를 사"
"용합니다. 이 마이크로컨트롤러는 Nordic nRF51822 마이크로컨트롤러에 기반한 [개"
"발 보드](https://tech.microbit.org/hardware/)로써, LED와 버튼, I2C 연결 가속"
"도계 및 나침반, 온보드 SWD 디버거를 포함하고 있습니다."
#: src/bare-metal.md:20
msgid ""
"To get started, install some tools we'll need later. On gLinux or Debian:"
msgstr ""
"시작하기전에, 앞으로 사용할 도구를 설치해야 합니다. gLinux 또는 Debian를 사용"
"하고 있다면 아래와 같이 하세요."
#: src/bare-metal.md:22
msgid ""
"```bash\n"
"sudo apt install gcc-aarch64-linux-gnu gdb-multiarch libudev-dev picocom pkg-"
"config qemu-system-arm\n"
"rustup update\n"
"rustup target add aarch64-unknown-none thumbv7em-none-eabihf\n"
"rustup component add llvm-tools-preview\n"
"cargo install cargo-binutils cargo-embed\n"
"```"
msgstr ""
"```bash\n"
"sudo apt install gcc-aarch64-linux-gnu gdb-multiarch libudev-dev picocom pkg-"
"config qemu-system-arm\n"
"rustup update\n"
"rustup target add aarch64-unknown-none thumbv7em-none-eabihf\n"
"rustup component add llvm-tools-preview\n"
"cargo install cargo-binutils cargo-embed\n"
"```"
#: src/bare-metal.md:30
msgid ""
"And give users in the `plugdev` group access to the micro:bit programmer:"
msgstr ""
"`plugdev` 그룹의 사용자에게 micro:bit 프로그래머 장치에 대한 액세스 권한을 부"
"여합니다."
#: src/bare-metal.md:32
msgid ""
"```bash\n"
"echo 'SUBSYSTEM==\"usb\", ATTR{idVendor}==\"0d28\", MODE=\"0664\", "
"GROUP=\"plugdev\"' |\\\n"
" sudo tee /etc/udev/rules.d/50-microbit.rules\n"
"sudo udevadm control --reload-rules\n"
"```"
msgstr ""
"```bash\n"
"echo 'SUBSYSTEM==\"usb\", ATTR{idVendor}==\"0d28\", MODE=\"0664\", "
"GROUP=\"plugdev\"' |\\\n"
" sudo tee /etc/udev/rules.d/50-microbit.rules\n"
"sudo udevadm control --reload-rules\n"
"```"
#: src/bare-metal.md:38
msgid "On MacOS:"
msgstr "MacOS에서:"
#: src/bare-metal.md:40
msgid ""
"```bash\n"
"xcode-select --install\n"
"brew install gdb picocom qemu\n"
"brew install --cask gcc-aarch64-embedded\n"
"rustup update\n"
"rustup target add aarch64-unknown-none thumbv7em-none-eabihf\n"
"rustup component add llvm-tools-preview\n"
"cargo install cargo-binutils cargo-embed\n"
"```"
msgstr ""
"```bash\n"
"xcode-select --install\n"
"brew install gdb picocom qemu\n"
"brew install --cask gcc-aarch64-embedded\n"
"rustup update\n"
"rustup target add aarch64-unknown-none thumbv7em-none-eabihf\n"
"rustup component add llvm-tools-preview\n"
"cargo install cargo-binutils cargo-embed\n"
"```"
#: src/bare-metal/no_std.md:1
msgid "`no_std`"
msgstr "`no_std`"
#: src/bare-metal/no_std.md:7
msgid "`core`"
msgstr "`core`"
#: src/bare-metal/no_std.md:12 src/bare-metal/alloc.md:1
msgid "`alloc`"
msgstr "`alloc`"
#: src/bare-metal/no_std.md:17
msgid "`std`"
msgstr "`std`"
#: src/bare-metal/no_std.md:24
msgid "Slices, `&str`, `CStr`"
msgstr "Slices, `&str`, `CStr`"
#: src/bare-metal/no_std.md:25
msgid "`NonZeroU8`..."
msgstr "`NonZeroU8`..."
#: src/bare-metal/no_std.md:26
msgid "`Option`, `Result`"
msgstr "`Option`, `Result`"
#: src/bare-metal/no_std.md:27
msgid "`Display`, `Debug`, `write!`..."
msgstr "`Display`, `Debug`, `write!`..."
#: src/bare-metal/no_std.md:29
msgid "`panic!`, `assert_eq!`..."
msgstr "`panic!`, `assert_eq!`..."
#: src/bare-metal/no_std.md:30
msgid "`NonNull` and all the usual pointer-related functions"
msgstr "`NonNull` 및 모든 일반적인 포인터 관련 함수"
#: src/bare-metal/no_std.md:31
msgid "`Future` and `async`/`await`"
msgstr "`Future` and `async`/`await`"
#: src/bare-metal/no_std.md:32
msgid "`fence`, `AtomicBool`, `AtomicPtr`, `AtomicU32`..."
msgstr "`fence`, `AtomicBool`, `AtomicPtr`, `AtomicU32`..."
#: src/bare-metal/no_std.md:33
msgid "`Duration`"
msgstr "`Duration`"
#: src/bare-metal/no_std.md:38
msgid "`Box`, `Cow`, `Arc`, `Rc`"
msgstr "`Box`, `Cow`, `Arc`, `Rc`"
#: src/bare-metal/no_std.md:39
msgid "`Vec`, `BinaryHeap`, `BtreeMap`, `LinkedList`, `VecDeque`"
msgstr "`Vec`, `BinaryHeap`, `BtreeMap`, `LinkedList`, `VecDeque`"
#: src/bare-metal/no_std.md:40
msgid "`String`, `CString`, `format!`"
msgstr "`String`, `CString`, `format!`"
#: src/bare-metal/no_std.md:45
msgid "`Error`"
msgstr "`Error`"
#: src/bare-metal/no_std.md:47
msgid "`Mutex`, `Condvar`, `Barrier`, `Once`, `RwLock`, `mpsc`"
msgstr "`Mutex`, `Condvar`, `Barrier`, `Once`, `RwLock`, `mpsc`"
#: src/bare-metal/no_std.md:48
msgid "`File` and the rest of `fs`"
msgstr "`File` 및 나머지 `fs`"
#: src/bare-metal/no_std.md:49
msgid "`println!`, `Read`, `Write`, `Stdin`, `Stdout` and the rest of `io`"
msgstr "`println!`, `Read`, `Write`, `Stdin`, `Stdout` 및 나머지 `io`"
#: src/bare-metal/no_std.md:50
msgid "`Path`, `OsString`"
msgstr "`Path`, `OsString`"
#: src/bare-metal/no_std.md:51
msgid "`net`"
msgstr "`net`"
#: src/bare-metal/no_std.md:52
msgid "`Command`, `Child`, `ExitCode`"
msgstr "`Command`, `Child`, `ExitCode`"
#: src/bare-metal/no_std.md:53
msgid "`spawn`, `sleep` and the rest of `thread`"
msgstr "`spawn`, `sleep` 및 나머지 `thread`"
#: src/bare-metal/no_std.md:54
msgid "`SystemTime`, `Instant`"
msgstr "`SystemTime`, `Instant`"
#: src/bare-metal/no_std.md:62
msgid "`HashMap` depends on RNG."
msgstr "`HashMap`은 RNG에 의존합니다."
#: src/bare-metal/no_std.md:63
msgid "`std` re-exports the contents of both `core` and `alloc`."
msgstr "`std`는 `core` 및 `alloc`를 포함합니다."
#: src/bare-metal/minimal.md:1
msgid "A minimal `no_std` program"
msgstr "최소한의 `no_std` 프로그램"
#: src/bare-metal/minimal.md:3
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"use core::panic::PanicInfo;\n"
"\n"
"#[panic_handler]\n"
"fn panic(_panic: &PanicInfo) -> ! {\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"use core::panic::PanicInfo;\n"
"\n"
"#[panic_handler]\n"
"fn panic(_panic: &PanicInfo) -> ! {\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/minimal.md:17
msgid "This will compile to an empty binary."
msgstr "이 코드는 빈 바이너리로 컴파일됩니다."
#: src/bare-metal/minimal.md:18
msgid "`std` provides a panic handler; without it we must provide our own."
msgstr ""
"`std`는 패닉 핸들러를 제공하지만, 우리는 자체적으로 핸들러를 만들어야합니다."
#: src/bare-metal/minimal.md:19
msgid "It can also be provided by another crate, such as `panic-halt`."
msgstr "패닉 핸들러는 `panic-halt`와 같은 크레이트를 통해서 만들수도 있습니다."
#: src/bare-metal/minimal.md:20
msgid ""
"Depending on the target, you may need to compile with `panic = \"abort\"` to "
"avoid an error about `eh_personality`."
msgstr ""
"타겟에 따라 `panic = \"abort\"`로 컴파일해야 할 수 있습니다. 이는 "
"`eh_personality`에 관한 오류를 방지하기 위함입니다."
#: src/bare-metal/minimal.md:22
msgid ""
"Note that there is no `main` or any other entry point; it's up to you to "
"define your own entry point. This will typically involve a linker script and "
"some assembly code to set things up ready for Rust code to run."
msgstr ""
"`main` 과 같은 프로그램 진입점이 없습니다. 개발자가 자체적으로 진입점을 정의"
"해야 합니다. 진입점을 정의하는 작업은, 일반적으로 링커 스크립트와 어셈블리 코"
"드를 필요로 합니다."
#: src/bare-metal/alloc.md:3
msgid ""
"To use `alloc` you must implement a [global (heap) allocator](https://doc."
"rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html)."
msgstr ""
"`alloc`을 사용하려면 [전역 (힙) 할당자](https://doc.rust-lang.org/stable/std/"
"alloc/trait.GlobalAlloc.html)를 구현해야 합니다."
#: src/bare-metal/alloc.md:6
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate alloc;\n"
"extern crate panic_halt as _;\n"
"\n"
"use alloc::string::ToString;\n"
"use alloc::vec::Vec;\n"
"use buddy_system_allocator::LockedHeap;\n"
"\n"
"#[global_allocator]\n"
"static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();\n"
"\n"
"static mut HEAP: [u8; 65536] = [0; 65536];\n"
"\n"
"pub fn entry() {\n"
" // Safe because `HEAP` is only used here and `entry` is only called "
"once.\n"
" unsafe {\n"
" // Give the allocator some memory to allocate.\n"
" HEAP_ALLOCATOR\n"
" .lock()\n"
" .init(HEAP.as_mut_ptr() as usize, HEAP.len());\n"
" }\n"
"\n"
" // Now we can do things that require heap allocation.\n"
" let mut v = Vec::new();\n"
" v.push(\"A string\".to_string());\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate alloc;\n"
"extern crate panic_halt as _;\n"
"\n"
"use alloc::string::ToString;\n"
"use alloc::vec::Vec;\n"
"use buddy_system_allocator::LockedHeap;\n"
"\n"
"#[global_allocator]\n"
"static HEAP_ALLOCATOR: LockedHeap<32> = LockedHeap::<32>::new();\n"
"\n"
"static mut HEAP: [u8; 65536] = [0; 65536];\n"
"\n"
"pub fn entry() {\n"
" // Safe because `HEAP` is only used here and `entry` is only called "
"once.\n"
" unsafe {\n"
" // Give the allocator some memory to allocate.\n"
" HEAP_ALLOCATOR\n"
" .lock()\n"
" .init(HEAP.as_mut_ptr() as usize, HEAP.len());\n"
" }\n"
"\n"
" // 이제 힙 할당이 필요한 작업을 실행할 수 있습니다.\n"
" let mut v = Vec::new();\n"
" v.push(\"A string\".to_string());\n"
"}\n"
"```"
#: src/bare-metal/alloc.md:39
msgid ""
"`buddy_system_allocator` is a third-party crate implementing a basic buddy "
"system allocator. Other crates are available, or you can write your own or "
"hook into your existing allocator."
msgstr ""
"`buddy_system_allocator`는 간단한 버디 시스템 할당자를 구현하는 서드 파티 크"
"레이트입니다. 이 외에도, 다른 크레이트를 사용하거나, 직접 할당자를 만들거나, "
"이미 존재하는 다른 할당자에 후킹할 수 있습니다."
#: src/bare-metal/alloc.md:41
msgid ""
"The const parameter of `LockedHeap` is the max order of the allocator; i.e. "
"in this case it can allocate regions of up to 2\\*\\*32 bytes."
msgstr ""
"`LockHeap` 타입의 const 매개변수는 할당자의 최대 크기를 2진수로 표현했을 때"
"의 자릿수입니다. 즉, 이 경우처럼 32인 경우 최대 2\\*\\*32바이트 크기의 영역"
"을 다룰 수 있습니다."
#: src/bare-metal/alloc.md:43
msgid ""
"If any crate in your dependency tree depends on `alloc` then you must have "
"exactly one global allocator defined in your binary. Usually this is done in "
"the top-level binary crate."
msgstr ""
"한 바이너리에서 `alloc`에 의존하는 크레이트가 하나라도 있다면 바이너리 전체에"
"서 전역 할당자가 반드시 하나 존재해야 합니다. 일반적으로 전역 할당자를 선언하"
"는 작업은 최상위 바이너리 크레이트에서 이루어집니다."
#: src/bare-metal/alloc.md:45
msgid ""
"`extern crate panic_halt as _` is necessary to ensure that the `panic_halt` "
"crate is linked in so we get its panic handler."
msgstr ""
"`panic_halt` 크레이트가 연결되어 패닉 핸들러를 가져오도록 하려면 `extern "
"crate panic_halt as _`가 필요합니다."
#: src/bare-metal/alloc.md:47
msgid "This example will build but not run, as it doesn't have an entry point."
msgstr ""
"이 예시 코드는 빌드는 되지만, 진입점이 없기 때문에 실행되지는 않습니다."
#: src/bare-metal/microcontrollers.md:3
msgid ""
"The `cortex_m_rt` crate provides (among other things) a reset handler for "
"Cortex M microcontrollers."
msgstr ""
"'cortex_m_rt' 크레이트는 Cortex M 마이크로컨트롤러를 초기화 하는 핸들러를 제"
"공합니다."
#: src/bare-metal/microcontrollers.md:5
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"mod interrupts;\n"
"\n"
"use cortex_m_rt::entry;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"mod interrupts;\n"
"\n"
"use cortex_m_rt::entry;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/microcontrollers.md:21
msgid ""
"Next we'll look at how to access peripherals, with increasing levels of "
"abstraction."
msgstr ""
"이제, 주변장치에 액세스하는 방법을 알아보겠습니다. 가장 기계에 가까운 낮은 단"
"계에서 시작해서 점점 추상화 수준을 올리겠습니다."
#: src/bare-metal/microcontrollers.md:25
msgid ""
"The `cortex_m_rt::entry` macro requires that the function have type `fn() -"
"> !`, because returning to the reset handler doesn't make sense."
msgstr ""
"`cortex_m_rt::entry` 매크로는 진입점으로 사용되는 함수가`fn() -> !` 타입(즉, "
"리턴하지 않는)임을 요구합니다. 만약, 리턴하게 되면, 프로그램 수행 후 리셋 핸"
"들러로 돌아가게 되는 것인데 이는 말이 되지 않기 때문입니다."
#: src/bare-metal/microcontrollers.md:27
msgid "Run the example with `cargo embed --bin minimal`"
msgstr "`cargo embed --bin minimal`을 사용하여 예시를 실행합니다."
#: src/bare-metal/microcontrollers/mmio.md:3
msgid ""
"Most microcontrollers access peripherals via memory-mapped IO. Let's try "
"turning on an LED on our micro:bit:"
msgstr ""
"대부분의 마이크로컨트롤러는 메모리 매핑 IO를 통해 주변기기에 액세스합니다. "
"micro:bit에서 LED를 켜보겠습니다."
#: src/bare-metal/microcontrollers/mmio.md:6
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"mod interrupts;\n"
"\n"
"use core::mem::size_of;\n"
"use cortex_m_rt::entry;\n"
"\n"
"/// GPIO port 0 peripheral address\n"
"const GPIO_P0: usize = 0x5000_0000;\n"
"\n"
"// GPIO peripheral offsets\n"
"const PIN_CNF: usize = 0x700;\n"
"const OUTSET: usize = 0x508;\n"
"const OUTCLR: usize = 0x50c;\n"
"\n"
"// PIN_CNF fields\n"
"const DIR_OUTPUT: u32 = 0x1;\n"
"const INPUT_DISCONNECT: u32 = 0x1 << 1;\n"
"const PULL_DISABLED: u32 = 0x0 << 2;\n"
"const DRIVE_S0S1: u32 = 0x0 << 8;\n"
"const SENSE_DISABLED: u32 = 0x0 << 16;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n"
" let pin_cnf_21 = (GPIO_P0 + PIN_CNF + 21 * size_of::<u32>()) as *mut "
"u32;\n"
" let pin_cnf_28 = (GPIO_P0 + PIN_CNF + 28 * size_of::<u32>()) as *mut "
"u32;\n"
" // Safe because the pointers are to valid peripheral control registers, "
"and\n"
" // no aliases exist.\n"
" unsafe {\n"
" pin_cnf_21.write_volatile(\n"
" DIR_OUTPUT | INPUT_DISCONNECT | PULL_DISABLED | DRIVE_S0S1 | "
"SENSE_DISABLED,\n"
" );\n"
" pin_cnf_28.write_volatile(\n"
" DIR_OUTPUT | INPUT_DISCONNECT | PULL_DISABLED | DRIVE_S0S1 | "
"SENSE_DISABLED,\n"
" );\n"
" }\n"
"\n"
" // Set pin 28 low and pin 21 high to turn the LED on.\n"
" let gpio0_outset = (GPIO_P0 + OUTSET) as *mut u32;\n"
" let gpio0_outclr = (GPIO_P0 + OUTCLR) as *mut u32;\n"
" // Safe because the pointers are to valid peripheral control registers, "
"and\n"
" // no aliases exist.\n"
" unsafe {\n"
" gpio0_outclr.write_volatile(1 << 28);\n"
" gpio0_outset.write_volatile(1 << 21);\n"
" }\n"
"\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"mod interrupts;\n"
"\n"
"use core::mem::size_of;\n"
"use cortex_m_rt::entry;\n"
"\n"
"/// GPIO 포트 0 주변기기 주소입니다.\n"
"const GPIO_P0: usize = 0x5000_0000;\n"
"\n"
"// GPIO 주변기기 오프셋입니다.\n"
"const PIN_CNF: usize = 0x700;\n"
"const OUTSET: usize = 0x508;\n"
"const OUTCLR: usize = 0x50c;\n"
"\n"
"// PIN_CNF 필드입니다.\n"
"const DIR_OUTPUT: u32 = 0x1;\n"
"const INPUT_DISCONNECT: u32 = 0x1 << 1;\n"
"const PULL_DISABLED: u32 = 0x0 << 2;\n"
"const DRIVE_S0S1: u32 = 0x0 << 8;\n"
"const SENSE_DISABLED: u32 = 0x0 << 16;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n"
" let pin_cnf_21 = (GPIO_P0 + PIN_CNF + 21 * size_of::<u32>()) as *mut "
"u32;\n"
" let pin_cnf_28 = (GPIO_P0 + PIN_CNF + 28 * size_of::<u32>()) as *mut "
"u32;\n"
" // Safe because the pointers are to valid peripheral control registers, "
"and\n"
" // no aliases exist.\n"
" unsafe {\n"
" pin_cnf_21.write_volatile(\n"
" DIR_OUTPUT | INPUT_DISCONNECT | PULL_DISABLED | DRIVE_S0S1 | "
"SENSE_DISABLED,\n"
" );\n"
" pin_cnf_28.write_volatile(\n"
" DIR_OUTPUT | INPUT_DISCONNECT | PULL_DISABLED | DRIVE_S0S1 | "
"SENSE_DISABLED,\n"
" );\n"
" }\n"
"\n"
" // 핀 28을 low로, 핀 21을 high로 설정하여 LED을 켭니다.\n"
" let gpio0_outset = (GPIO_P0 + OUTSET) as *mut u32;\n"
" let gpio0_outclr = (GPIO_P0 + OUTCLR) as *mut u32;\n"
" // 포인터가 유효한 주변기기 컨트롤 레지스터에 관한 것이므로 안전하고\n"
" // 별칭이 없습니다.\n"
" unsafe {\n"
" gpio0_outclr.write_volatile(1 << 28);\n"
" gpio0_outset.write_volatile(1 << 21);\n"
" }\n"
"\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/microcontrollers/mmio.md:64
msgid ""
"GPIO 0 pin 21 is connected to the first column of the LED matrix, and pin 28 "
"to the first row."
msgstr ""
"GPIO 0 핀 21은 LED 매트릭스의 첫 번째 열에 연결되고 핀 28은 첫 번째 행에 연결"
"됩니다."
#: src/bare-metal/microcontrollers/mmio.md:66
#: src/bare-metal/microcontrollers/pacs.md:59
#: src/bare-metal/microcontrollers/hals.md:43
#: src/bare-metal/microcontrollers/board-support.md:34
msgid "Run the example with:"
msgstr "아래 명령어로 예제 코드를 실행하세요."
#: src/bare-metal/microcontrollers/mmio.md:68
msgid ""
"```sh\n"
"cargo embed --bin mmio\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin mmio\n"
"```"
#: src/bare-metal/microcontrollers/pacs.md:1
msgid "Peripheral Access Crates"
msgstr "주변기기 액세스 크레이트"
#: src/bare-metal/microcontrollers/pacs.md:3
msgid ""
"[`svd2rust`](https://crates.io/crates/svd2rust) generates mostly-safe Rust "
"wrappers for memory-mapped peripherals from [CMSIS-SVD](https://www.keil.com/"
"pack/doc/CMSIS/SVD/html/index.html) files."
msgstr ""
"[`svd2rust`](https://crates.io/crates/svd2rust) 크레이트를 이용하면 메모리 매"
"핑된 주변장치를 기술하는 [CMSIS-SVD](https://www.keil.com/pack/doc/CMSIS/SVD/"
"html/index.html) 파일로부터 Rust 래퍼를 생성할 수 있습니다."
#: src/bare-metal/microcontrollers/pacs.md:7
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use cortex_m_rt::entry;\n"
"use nrf52833_pac::Peripherals;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let p = Peripherals::take().unwrap();\n"
" let gpio0 = p.P0;\n"
"\n"
" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n"
" gpio0.pin_cnf[21].write(|w| {\n"
" w.dir().output();\n"
" w.input().disconnect();\n"
" w.pull().disabled();\n"
" w.drive().s0s1();\n"
" w.sense().disabled();\n"
" w\n"
" });\n"
" gpio0.pin_cnf[28].write(|w| {\n"
" w.dir().output();\n"
" w.input().disconnect();\n"
" w.pull().disabled();\n"
" w.drive().s0s1();\n"
" w.sense().disabled();\n"
" w\n"
" });\n"
"\n"
" // Set pin 28 low and pin 21 high to turn the LED on.\n"
" gpio0.outclr.write(|w| w.pin28().clear());\n"
" gpio0.outset.write(|w| w.pin21().set());\n"
"\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use cortex_m_rt::entry;\n"
"use nrf52833_pac::Peripherals;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let p = Peripherals::take().unwrap();\n"
" let gpio0 = p.P0;\n"
"\n"
" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n"
" gpio0.pin_cnf[21].write(|w| {\n"
" w.dir().output();\n"
" w.input().disconnect();\n"
" w.pull().disabled();\n"
" w.drive().s0s1();\n"
" w.sense().disabled();\n"
" w\n"
" });\n"
" gpio0.pin_cnf[28].write(|w| {\n"
" w.dir().output();\n"
" w.input().disconnect();\n"
" w.pull().disabled();\n"
" w.drive().s0s1();\n"
" w.sense().disabled();\n"
" w\n"
" });\n"
"\n"
" // 핀 28을 low로, 핀 21을 high로 설정하여 LED를 켭니다.\n"
" gpio0.outclr.write(|w| w.pin28().clear());\n"
" gpio0.outset.write(|w| w.pin21().set());\n"
"\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/microcontrollers/pacs.md:49
msgid ""
"SVD (System View Description) files are XML files typically provided by "
"silicon vendors which describe the memory map of the device."
msgstr ""
"SVD(System View Description) 파일은 일반적으로 실리콘 공급업체에서 제공하는 "
"XML 파일로, 기기의 메모리 맵을 기술합니다."
#: src/bare-metal/microcontrollers/pacs.md:51
msgid ""
"They are organised by peripheral, register, field and value, with names, "
"descriptions, addresses and so on."
msgstr ""
"주변기기, 레지스터, 필드, 값으로 구성되며 이름, 설명, 주소 등이 포함됩니다."
#: src/bare-metal/microcontrollers/pacs.md:53
msgid ""
"SVD files are often buggy and incomplete, so there are various projects "
"which patch the mistakes, add missing details, and publish the generated "
"crates."
msgstr ""
"SVD 파일에는 버그가 있을 수 있고 불완전하기 때문에, 이러한 문제들을 패치하는 "
"다양한 프로젝트들이 있습니다."
#: src/bare-metal/microcontrollers/pacs.md:55
msgid "`cortex-m-rt` provides the vector table, among other things."
msgstr "`cortex-m-rt`는 무엇보다도 벡터 테이블을 제공합니다."
#: src/bare-metal/microcontrollers/pacs.md:56
msgid ""
"If you `cargo install cargo-binutils` then you can run `cargo objdump --bin "
"pac -- -d --no-show-raw-insn` to see the resulting binary."
msgstr ""
"`cargo install cargo-binutils`을 실행한 후, `cargo objdump --bin pac -- -d --"
"no-show-raw-insn`을 실행하여 생성된 바이너리의 내용을 확인할 수 있습니다."
#: src/bare-metal/microcontrollers/pacs.md:61
msgid ""
"```sh\n"
"cargo embed --bin pac\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin pac\n"
"```"
#: src/bare-metal/microcontrollers/hals.md:1
msgid "HAL crates"
msgstr "HAL 크레이트들"
#: src/bare-metal/microcontrollers/hals.md:3
msgid ""
"[HAL crates](https://github.com/rust-embedded/awesome-embedded-rust#hal-"
"implementation-crates) for many microcontrollers provide wrappers around "
"various peripherals. These generally implement traits from [`embedded-hal`]"
"(https://crates.io/crates/embedded-hal)."
msgstr ""
"다양한 주변 장치에 대한 래퍼를 제공하는 [HAL 크레이트](https://github.com/"
"rust-embedded/awesome-embedded-rust#hal-implementation-crates)들이 있습니다. "
"이 크레이트들은 일반적으로 [`embedded-hal`](https://crates.io/crates/"
"embedded-hal)의 트레잇을 구현합니다."
#: src/bare-metal/microcontrollers/hals.md:7
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use cortex_m_rt::entry;\n"
"use nrf52833_hal::gpio::{p0, Level};\n"
"use nrf52833_hal::pac::Peripherals;\n"
"use nrf52833_hal::prelude::*;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let p = Peripherals::take().unwrap();\n"
"\n"
" // Create HAL wrapper for GPIO port 0.\n"
" let gpio0 = p0::Parts::new(p.P0);\n"
"\n"
" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n"
" let mut col1 = gpio0.p0_28.into_push_pull_output(Level::High);\n"
" let mut row1 = gpio0.p0_21.into_push_pull_output(Level::Low);\n"
"\n"
" // Set pin 28 low and pin 21 high to turn the LED on.\n"
" col1.set_low().unwrap();\n"
" row1.set_high().unwrap();\n"
"\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use cortex_m_rt::entry;\n"
"use nrf52833_hal::gpio::{p0, Level};\n"
"use nrf52833_hal::pac::Peripherals;\n"
"use nrf52833_hal::prelude::*;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let p = Peripherals::take().unwrap();\n"
"\n"
" // Create HAL wrapper for GPIO port 0.\n"
" let gpio0 = p0::Parts::new(p.P0);\n"
"\n"
" // Configure GPIO 0 pins 21 and 28 as push-pull outputs.\n"
" let mut col1 = gpio0.p0_28.into_push_pull_output(Level::High);\n"
" let mut row1 = gpio0.p0_21.into_push_pull_output(Level::Low);\n"
"\n"
" // Set pin 28 low and pin 21 high to turn the LED on.\n"
" col1.set_low().unwrap();\n"
" row1.set_high().unwrap();\n"
"\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/microcontrollers/hals.md:39
msgid ""
"`set_low` and `set_high` are methods on the `embedded_hal` `OutputPin` trait."
msgstr ""
"`set_low` 및 `set_high`는 `embedded_hal` `OutputPin` 트레잇의 메서드입니다."
#: src/bare-metal/microcontrollers/hals.md:40
msgid ""
"HAL crates exist for many Cortex-M and RISC-V devices, including various "
"STM32, GD32, nRF, NXP, MSP430, AVR and PIC microcontrollers."
msgstr ""
"다양한 STM32, GD32, nRF, NXP, MSP430, AVR, PIC 마이크로컨트롤러를 비롯한 많"
"은 Cortex-M 및 RISC-V 기기를 위한 HAL 크레이트가 있습니다"
#: src/bare-metal/microcontrollers/hals.md:45
msgid ""
"```sh\n"
"cargo embed --bin hal\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin hal\n"
"```"
#: src/bare-metal/microcontrollers/board-support.md:1
#, fuzzy
msgid "Board support crates"
msgstr "보드 지원 크레이트"
#: src/bare-metal/microcontrollers/board-support.md:3
msgid ""
"Board support crates provide a further level of wrapping for a specific "
"board for convenience."
msgstr ""
"보드 지원 크레이트들은, 특정 보드를 더 손쉽게 사용할 수 있게 해 주는 더 높은 "
"수준의 추상화를 제공합니다."
#: src/bare-metal/microcontrollers/board-support.md:5
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use cortex_m_rt::entry;\n"
"use microbit::hal::prelude::*;\n"
"use microbit::Board;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let mut board = Board::take().unwrap();\n"
"\n"
" board.display_pins.col1.set_low().unwrap();\n"
" board.display_pins.row1.set_high().unwrap();\n"
"\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use cortex_m_rt::entry;\n"
"use microbit::hal::prelude::*;\n"
"use microbit::Board;\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let mut board = Board::take().unwrap();\n"
"\n"
" board.display_pins.col1.set_low().unwrap();\n"
" board.display_pins.row1.set_high().unwrap();\n"
"\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/microcontrollers/board-support.md:28
msgid ""
"In this case the board support crate is just providing more useful names, "
"and a bit of initialisation."
msgstr ""
"이 경우 보드 지원 크레이트는 좀 더 직관적인 이름들과 적당한 수준의 초기화를 "
"제공합니다."
#: src/bare-metal/microcontrollers/board-support.md:30
msgid ""
"The crate may also include drivers for some on-board devices outside of the "
"microcontroller itself."
msgstr ""
"이 크레이트는 마이크로컨트롤 밖에 있는 (즉, 보드에 설치된) 장치에 대한 드라이"
"버도 포함할 수 있습니다."
#: src/bare-metal/microcontrollers/board-support.md:32
msgid "`microbit-v2` includes a simple driver for the LED matrix."
msgstr ""
"`microbit-v2`에는 LED 매트릭스를 위한 간단한 드라이버가 포함되어 있습니다."
#: src/bare-metal/microcontrollers/board-support.md:36
msgid ""
"```sh\n"
"cargo embed --bin board_support\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin board_support\n"
"```"
#: src/bare-metal/microcontrollers/type-state.md:1
msgid "The type state pattern"
msgstr "타입 상태 패턴"
#: src/bare-metal/microcontrollers/type-state.md:3
msgid ""
"```rust,editable,compile_fail\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let p = Peripherals::take().unwrap();\n"
" let gpio0 = p0::Parts::new(p.P0);\n"
"\n"
" let pin: P0_01<Disconnected> = gpio0.p0_01;\n"
"\n"
" // let gpio0_01_again = gpio0.p0_01; // Error, moved.\n"
" let pin_input: P0_01<Input<Floating>> = pin.into_floating_input();\n"
" if pin_input.is_high().unwrap() {\n"
" // ...\n"
" }\n"
" let mut pin_output: P0_01<Output<OpenDrain>> = pin_input\n"
" .into_open_drain_output(OpenDrainConfig::Disconnect0Standard1, "
"Level::Low);\n"
" pin_output.set_high().unwrap();\n"
" // pin_input.is_high(); // Error, moved.\n"
"\n"
" let _pin2: P0_02<Output<OpenDrain>> = gpio0\n"
" .p0_02\n"
" .into_open_drain_output(OpenDrainConfig::Disconnect0Standard1, "
"Level::Low);\n"
" let _pin3: P0_03<Output<PushPull>> = gpio0.p0_03."
"into_push_pull_output(Level::Low);\n"
"\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let p = Peripherals::take().unwrap();\n"
" let gpio0 = p0::Parts::new(p.P0);\n"
"\n"
" let pin: P0_01<Disconnected> = gpio0.p0_01;\n"
"\n"
" // let gpio0_01_again = gpio0.p0_01; // Error, moved.\n"
" let pin_input: P0_01<Input<Floating>> = pin.into_floating_input();\n"
" if pin_input.is_high().unwrap() {\n"
" // ...\n"
" }\n"
" let mut pin_output: P0_01<Output<OpenDrain>> = pin_input\n"
" .into_open_drain_output(OpenDrainConfig::Disconnect0Standard1, "
"Level::Low);\n"
" pin_output.set_high().unwrap();\n"
" // pin_input.is_high(); // 오류, 이동했습니다.\n"
"\n"
" let _pin2: P0_02<Output<OpenDrain>> = gpio0\n"
" .p0_02\n"
" .into_open_drain_output(OpenDrainConfig::Disconnect0Standard1, "
"Level::Low);\n"
" let _pin3: P0_03<Output<PushPull>> = gpio0.p0_03."
"into_push_pull_output(Level::Low);\n"
"\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/microcontrollers/type-state.md:32
msgid ""
"Pins don't implement `Copy` or `Clone`, so only one instance of each can "
"exist. Once a pin is moved out of the port struct nobody else can take it."
msgstr ""
"핀은 `Copy` 또는 `Clone`을 구현하지 않으므로 각각 하나의 인스턴스만 존재할 "
"수 있습니다. 핀을 포트 구조체 밖으로 이동하면 아무도 사용할 수 없습니다."
#: src/bare-metal/microcontrollers/type-state.md:34
msgid ""
"Changing the configuration of a pin consumes the old pin instance, so you "
"can’t keep use the old instance afterwards."
msgstr ""
"핀 구성을 변경하면 이전 핀 인스턴스가 사용되므로 이후에 이전 인스턴스를 계속 "
"사용할 수 없습니다."
#: src/bare-metal/microcontrollers/type-state.md:36
msgid ""
"The type of a value indicates the state that it is in: e.g. in this case, "
"the configuration state of a GPIO pin. This encodes the state machine into "
"the type system, and ensures that you don't try to use a pin in a certain "
"way without properly configuring it first. Illegal state transitions are "
"caught at compile time."
msgstr ""
"값 유형은 현재 상태를 나타냅니다. 예를 들어 이 경우에는 GPIO 핀의 구성 상태입"
"니다. 이렇게 하면 상태 머신이 유형 시스템으로 인코딩되며, 먼저 올바르게 구성"
"한 후 특정 방식으로 핀을 사용하도록 합니다. 잘못된 상태 전환은 컴파일 시간에 "
"포착됩니다."
#: src/bare-metal/microcontrollers/type-state.md:40
msgid ""
"You can call `is_high` on an input pin and `set_high` on an output pin, but "
"not vice-versa."
msgstr ""
"입력 핀에서 `is_high`를 호출하고 출력 핀에서 `set_high`를 호출할 수 있지만 "
"그 반대로는 안 됩니다."
#: src/bare-metal/microcontrollers/type-state.md:41
msgid "Many HAL crates follow this pattern."
msgstr "많은 HAL 크레이트들이 이 패턴을 따릅니다."
#: src/bare-metal/microcontrollers/embedded-hal.md:1
msgid "`embedded-hal`"
msgstr "`embedded-hal`"
#: src/bare-metal/microcontrollers/embedded-hal.md:3
msgid ""
"The [`embedded-hal`](https://crates.io/crates/embedded-hal) crate provides a "
"number of traits covering common microcontroller peripherals."
msgstr ""
"[`embedded-hal`](https://crates.io/crates/embedded-hal) 크레이트는 다양한 마"
"이크로컨트롤러에서 공통적으로 찾아볼 수 있는 주변기기를 추상회 하는 다양한 트"
"레잇을 제공합니다."
#: src/bare-metal/microcontrollers/embedded-hal.md:6
msgid "GPIO"
msgstr "GPIO"
#: src/bare-metal/microcontrollers/embedded-hal.md:7
msgid "ADC"
msgstr "ADC"
#: src/bare-metal/microcontrollers/embedded-hal.md:8
msgid "I2C, SPI, UART, CAN"
msgstr "I2C, SPI, UART, CAN"
#: src/bare-metal/microcontrollers/embedded-hal.md:9
msgid "RNG"
msgstr "RNG"
#: src/bare-metal/microcontrollers/embedded-hal.md:10
msgid "Timers"
msgstr "타이머"
#: src/bare-metal/microcontrollers/embedded-hal.md:11
msgid "Watchdogs"
msgstr "워치독"
#: src/bare-metal/microcontrollers/embedded-hal.md:13
msgid ""
"Other crates then implement [drivers](https://github.com/rust-embedded/"
"awesome-embedded-rust#driver-crates) in terms of these traits, e.g. an "
"accelerometer driver might need an I2C or SPI bus implementation."
msgstr ""
"그러면 다른 크레이트는 이 트레잇들을 활용하여 [드라이버](https://github.com/"
"rust-embedded/awesome-embedded-rust#driver-crates)를 구현합니다. 예를 들어 가"
"속도계 드라이버를 구현할 떄 I2C 또는 SPI 버스 구현을 사용할 수 있습니다."
#: src/bare-metal/microcontrollers/embedded-hal.md:19
msgid ""
"There are implementations for many microcontrollers, as well as other "
"platforms such as Linux on Raspberry Pi."
msgstr ""
"라스베리 파이에서 돌아가는 리눅스 같은 플랫폼 뿐만 아니라 다른 여러 마이크로"
"컨트롤러에 대한 구현이 있습니다."
#: src/bare-metal/microcontrollers/embedded-hal.md:21
msgid ""
"There is work in progress on an `async` version of `embedded-hal`, but it "
"isn't stable yet."
msgstr ""
"`embedded-hal`의 'async' 버전에 관한 작업이 진행 중이지만 아직 안정적이지 않"
"습니다."
#: src/bare-metal/microcontrollers/probe-rs.md:1
msgid "`probe-rs`, `cargo-embed`"
msgstr "`probe-rs`, `cargo-embed`"
#: src/bare-metal/microcontrollers/probe-rs.md:3
msgid ""
"[probe-rs](https://probe.rs/) is a handy toolset for embedded debugging, "
"like OpenOCD but better integrated."
msgstr ""
"[probe-rs](https://probe.rs/)는 임베디드 시스템을 위한 도구 모임입니다. "
"OpenOCD와 비슷하지만, Rust에 더 잘 통합되어 있습니다."
#: src/bare-metal/microcontrollers/probe-rs.md:6
msgid "SWD"
msgstr "SWD"
#: src/bare-metal/microcontrollers/probe-rs.md:6
msgid " and JTAG via CMSIS-DAP, ST-Link and J-Link probes"
msgstr " 및 JTAG(CMSIS-DAP, ST-Link, J-Link 프로브를 통함)"
#: src/bare-metal/microcontrollers/probe-rs.md:7
msgid "GDB stub and Microsoft "
msgstr "GDB 스텁 및 Microsoft "
#: src/bare-metal/microcontrollers/probe-rs.md:7
msgid "DAP"
msgstr "DAP"
#: src/bare-metal/microcontrollers/probe-rs.md:7
msgid " server"
msgstr " 서버"
#: src/bare-metal/microcontrollers/probe-rs.md:8
msgid "Cargo integration"
msgstr "Cargo에 통합됨"
#: src/bare-metal/microcontrollers/probe-rs.md:10
msgid "`cargo-embed` is a cargo subcommand to build and flash binaries, log "
msgstr ""
"`cargo-embed`는 cargo의 서브 커맨트로써, 바이너리를 빌드하고 플래시하며, "
#: src/bare-metal/microcontrollers/probe-rs.md:11
msgid "RTT"
msgstr "RTT"
#: src/bare-metal/microcontrollers/probe-rs.md:11
msgid ""
" output and connect GDB. It's configured by an `Embed.toml` file in your "
"project directory."
msgstr ""
" 출력을 기록하고, GDB를 연결해 줍니다. 이 명령어의 세부 동작은 프로젝트 디렉"
"터리의 `Embed.toml` 파일을 통해 설정합니다."
#: src/bare-metal/microcontrollers/probe-rs.md:16
msgid ""
"[CMSIS-DAP](https://arm-software.github.io/CMSIS_5/DAP/html/index.html) is "
"an Arm standard protocol over USB for an in-circuit debugger to access the "
"CoreSight Debug Access Port of various Arm Cortex processors. It's what the "
"on-board debugger on the BBC micro:bit uses."
msgstr ""
"[CMSIS-DAP](https://arm-software.github.io/CMSIS_5/DAP/html/index.html)는 Arm"
"에서 정의한 프로토콜로, USB를 통해 Arm Cortex 프로세서의 CoreSight 디버그 액"
"세스 포트에 접근할 수 있게 해 줍니다. BBC micro:bit에 있는 온보드 디버거도 "
"이 프로토콜을 지원합니다."
#: src/bare-metal/microcontrollers/probe-rs.md:19
msgid ""
"ST-Link is a range of in-circuit debuggers from ST Microelectronics, J-Link "
"is a range from SEGGER."
msgstr ""
"ST-Link는 ST Microelectronics사에서 만든 in-circuit 디버거들이며, J-Link는 "
"SEGGER사의 in-circuit 디버거들입니다."
#: src/bare-metal/microcontrollers/probe-rs.md:21
msgid ""
"The Debug Access Port is usually either a 5-pin JTAG interface or 2-pin "
"Serial Wire Debug."
msgstr ""
"디버그 액세스 포트의 물리적인 구성은 일반적으로 5핀 JTAG 인터페이스 혹은, 2"
"핀 Serial Wire Debug 인터페이스 입니다."
#: src/bare-metal/microcontrollers/probe-rs.md:22
msgid ""
"probe-rs is a library which you can integrate into your own tools if you "
"want to."
msgstr ""
"probe-rs는 라이브러리로 구현되어 있어서, 다른 도구들에 통합되기가 쉽습니다."
#: src/bare-metal/microcontrollers/probe-rs.md:23
msgid ""
"The [Microsoft Debug Adapter Protocol](https://microsoft.github.io/debug-"
"adapter-protocol/) lets VSCode and other IDEs debug code running on any "
"supported microcontroller."
msgstr ""
"[Microsoft 디버그 어댑터 프로토콜](https://microsoft.github.io/debug-adapter-"
"protocol/)을 사용하면 VSCode나 다른 IDE 상에서 마이크로컨트롤러에서 수행중인 "
"코드를 디버깅 할 수 있습니다."
#: src/bare-metal/microcontrollers/probe-rs.md:25
msgid "cargo-embed is a binary built using the probe-rs library."
msgstr "cargo-embed는 probe-rs 라이브러리를 사용하여 빌드된 바이너리입니다."
#: src/bare-metal/microcontrollers/probe-rs.md:26
msgid ""
"RTT (Real Time Transfers) is a mechanism to transfer data between the debug "
"host and the target through a number of ringbuffers."
msgstr ""
"RTT(Real Time Transfers)는 여러 링 버퍼를 통해 디버그 호스트와 타겟 간에 데이"
"터를 전송하는 메커니즘입니다."
#: src/bare-metal/microcontrollers/debugging.md:3
msgid "Embed.toml:"
msgstr "Embed.toml:"
#: src/bare-metal/microcontrollers/debugging.md:5
msgid ""
"```toml\n"
"[default.general]\n"
"chip = \"nrf52833_xxAA\"\n"
"\n"
"[debug.gdb]\n"
"enabled = true\n"
"```"
msgstr ""
"```toml\n"
"[default.general]\n"
"chip = \"nrf52833_xxAA\"\n"
"\n"
"[debug.gdb]\n"
"enabled = true\n"
"```"
#: src/bare-metal/microcontrollers/debugging.md:13
msgid "In one terminal under `src/bare-metal/microcontrollers/examples/`:"
msgstr "`src/bare-metal/microcontrollers/examples/` 아래 하나의 터미널에서:"
#: src/bare-metal/microcontrollers/debugging.md:15
msgid ""
"```sh\n"
"cargo embed --bin board_support debug\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin board_support debug\n"
"```"
#: src/bare-metal/microcontrollers/debugging.md:19
#, fuzzy
msgid "In another terminal in the same directory:"
msgstr "다른 터미널을 띄워서 서비스가 잘 수행되고 있는지 확인합니다:"
#: src/bare-metal/microcontrollers/debugging.md:21
msgid ""
"```sh\n"
"gdb-multiarch target/thumbv7em-none-eabihf/debug/board_support --eval-"
"command=\"target remote :1337\"\n"
"```"
msgstr ""
"```sh\n"
"gdb-multiarch target/thumbv7em-none-eabihf/debug/board_support --eval-"
"command=\"target remote :1337\"\n"
"```"
#: src/bare-metal/microcontrollers/debugging.md:27
msgid "In GDB, try running:"
msgstr "GDB에서 다음을 실행해 보세요."
#: src/bare-metal/microcontrollers/debugging.md:29
msgid ""
"```gdb\n"
"b src/bin/board_support.rs:29\n"
"b src/bin/board_support.rs:30\n"
"b src/bin/board_support.rs:32\n"
"c\n"
"c\n"
"c\n"
"```"
msgstr ""
"```gdb\n"
"b src/bin/board_support.rs:29\n"
"b src/bin/board_support.rs:30\n"
"b src/bin/board_support.rs:32\n"
"c\n"
"c\n"
"c\n"
"```"
#: src/bare-metal/microcontrollers/other-projects.md:1
#: src/bare-metal/aps/other-projects.md:1
msgid "Other projects"
msgstr "다른 프로젝트"
#: src/bare-metal/microcontrollers/other-projects.md:3
msgid "[RTIC](https://rtic.rs/)"
msgstr "[RTIC](https://rtic.rs/)"
#: src/bare-metal/microcontrollers/other-projects.md:4
msgid "\"Real-Time Interrupt-driven Concurrency\""
msgstr ""
"\"실시간 인터럽트 기반 동시 실행(Real-Time Interrupt-driven Concurrency)\""
#: src/bare-metal/microcontrollers/other-projects.md:5
msgid ""
"Shared resource management, message passing, task scheduling, timer queue"
msgstr "공유 리소스 관리, 메시지 전달, 태스크 스케줄링, 타이머 대기열 지원"
#: src/bare-metal/microcontrollers/other-projects.md:6
msgid "[Embassy](https://embassy.dev/)"
msgstr "[Embassy](https://embassy.dev/)"
#: src/bare-metal/microcontrollers/other-projects.md:7
msgid "`async` executors with priorities, timers, networking, USB"
msgstr "우선순위, 타이머, 네트워킹, USB가 포함된 `async` 실행자"
#: src/bare-metal/microcontrollers/other-projects.md:8
msgid "[TockOS](https://www.tockos.org/documentation/getting-started)"
msgstr "[TockOS](https://www.tockos.org/documentation/getting-started)"
#: src/bare-metal/microcontrollers/other-projects.md:9
msgid ""
"Security-focused RTOS with preemptive scheduling and Memory Protection Unit "
"support"
msgstr "선점형 스케줄링 및 MMU를 지원하는, 보안에 중점을 둔 실시간 운영체제"
#: src/bare-metal/microcontrollers/other-projects.md:10
msgid "[Hubris](https://hubris.oxide.computer/)"
msgstr "[Hubris](https://hubris.oxide.computer/)"
#: src/bare-metal/microcontrollers/other-projects.md:11
msgid ""
"Microkernel RTOS from Oxide Computer Company with memory protection, "
"unprivileged drivers, IPC"
msgstr ""
"Oxide Computer Company에서 만든 마이크로커널 기반 실시간 운영체제로, 메모리 "
"보호, 권한이 없이 수행되는 드라이버 등을 지원함."
#: src/bare-metal/microcontrollers/other-projects.md:12
msgid "[Bindings for FreeRTOS](https://github.com/lobaro/FreeRTOS-rust)"
msgstr "[FreeRTOS용 바인딩](https://github.com/lobaro/FreeRTOS-rust)"
#: src/bare-metal/microcontrollers/other-projects.md:13
msgid ""
"Some platforms have `std` implementations, e.g. [esp-idf](https://esp-rs."
"github.io/book/overview/using-the-standard-library.html)."
msgstr ""
"`std`가 구현된 플랫폼도 있습니다(예: [esp-idf](https://esp-rs.github.io/book/"
"overview/using-the-standard-library.html))."
#: src/bare-metal/microcontrollers/other-projects.md:18
msgid "RTIC can be considered either an RTOS or a concurrency framework."
msgstr ""
"RTIC는 실시간 운영체제로 볼 수도 있고, 동시성 지원을 위한 프레임워크로 볼 수"
"도 있습니다."
#: src/bare-metal/microcontrollers/other-projects.md:19
msgid "It doesn't include any HALs."
msgstr "HAL을 포함하지는 않습니다."
#: src/bare-metal/microcontrollers/other-projects.md:20
msgid ""
"It uses the Cortex-M NVIC (Nested Virtual Interrupt Controller) for "
"scheduling rather than a proper kernel."
msgstr ""
"스케줄링은 커널이 아니라 Cortex-M NVIC(Nested Virtual Interrupt Controller)"
"로 구현이 됩니다."
#: src/bare-metal/microcontrollers/other-projects.md:22
msgid "Cortex-M only."
msgstr "Cortex-M 전용입니다."
#: src/bare-metal/microcontrollers/other-projects.md:23
msgid ""
"Google uses TockOS on the Haven microcontroller for Titan security keys."
msgstr ""
"Google에서는 Titan 보안 키에 사용되는 Haven 마이크로컨트롤러에서 TockOS를 사"
"용합니다."
#: src/bare-metal/microcontrollers/other-projects.md:24
msgid ""
"FreeRTOS is mostly written in C, but there are Rust bindings for writing "
"applications."
msgstr ""
"FreeRTOS는 대부분 C로 작성되지만, 애플리케이션을 Rust로 작성할 수 있도록 해 "
"주는 Rust 바인딩이 제공됩니다."
#: src/exercises/bare-metal/morning.md:3
msgid ""
"We will read the direction from an I2C compass, and log the readings to a "
"serial port."
msgstr ""
#: src/exercises/bare-metal/compass.md:3
msgid ""
"We will read the direction from an I2C compass, and log the readings to a "
"serial port. If you have time, try displaying it on the LEDs somehow too, or "
"use the buttons somehow."
msgstr ""
#: src/exercises/bare-metal/compass.md:6
msgid "Hints:"
msgstr ""
#: src/exercises/bare-metal/compass.md:8
msgid ""
"Check the documentation for the [`lsm303agr`](https://docs.rs/lsm303agr/"
"latest/lsm303agr/) and [`microbit-v2`](https://docs.rs/microbit-v2/latest/"
"microbit/) crates, as well as the [micro:bit hardware](https://tech.microbit."
"org/hardware/)."
msgstr ""
#: src/exercises/bare-metal/compass.md:11
msgid ""
"The LSM303AGR Inertial Measurement Unit is connected to the internal I2C bus."
msgstr ""
#: src/exercises/bare-metal/compass.md:12
msgid ""
"TWI is another name for I2C, so the I2C master peripheral is called TWIM."
msgstr ""
#: src/exercises/bare-metal/compass.md:13
msgid ""
"The LSM303AGR driver needs something implementing the `embedded_hal::"
"blocking::i2c::WriteRead` trait. The [`microbit::hal::Twim`](https://docs.rs/"
"microbit-v2/latest/microbit/hal/struct.Twim.html) struct implements this."
msgstr ""
#: src/exercises/bare-metal/compass.md:17
msgid ""
"You have a [`microbit::Board`](https://docs.rs/microbit-v2/latest/microbit/"
"struct.Board.html) struct with fields for the various pins and peripherals."
msgstr ""
#: src/exercises/bare-metal/compass.md:19
msgid ""
"You can also look at the [nRF52833 datasheet](https://infocenter.nordicsemi."
"com/pdf/nRF52833_PS_v1.5.pdf) if you want, but it shouldn't be necessary for "
"this exercise."
msgstr ""
#: src/exercises/bare-metal/compass.md:23
msgid ""
"Download the [exercise template](../../comprehensive-rust-exercises.zip) and "
"look in the `compass` directory for the following files."
msgstr ""
#: src/exercises/bare-metal/compass.md:26 src/exercises/bare-metal/rtc.md:19
#, fuzzy
msgid "`src/main.rs`:"
msgstr "_hello_rust/src/main.rs_:"
#: src/exercises/bare-metal/compass.md:30
msgid ""
"```rust,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use core::fmt::Write;\n"
"use cortex_m_rt::entry;\n"
"use microbit::{hal::uarte::{Baudrate, Parity, Uarte}, Board};\n"
"\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let board = Board::take().unwrap();\n"
"\n"
" // Configure serial port.\n"
" let mut serial = Uarte::new(\n"
" board.UARTE0,\n"
" board.uart.into(),\n"
" Parity::EXCLUDED,\n"
" Baudrate::BAUD115200,\n"
" );\n"
"\n"
" // Set up the I2C controller and Inertial Measurement Unit.\n"
" // TODO\n"
"\n"
" writeln!(serial, \"Ready.\").unwrap();\n"
"\n"
" loop {\n"
" // Read compass data and log it to the serial port.\n"
" // TODO\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/compass.md:64 src/exercises/bare-metal/rtc.md:385
msgid "`Cargo.toml` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/compass.md:68
msgid ""
"```toml\n"
"[workspace]\n"
"\n"
"[package]\n"
"name = \"compass\"\n"
"version = \"0.1.0\"\n"
"edition = \"2021\"\n"
"publish = false\n"
"\n"
"[dependencies]\n"
"cortex-m-rt = \"0.7.3\"\n"
"embedded-hal = \"0.2.6\"\n"
"lsm303agr = \"0.2.2\"\n"
"microbit-v2 = \"0.13.0\"\n"
"panic-halt = \"0.2.0\"\n"
"```"
msgstr ""
#: src/exercises/bare-metal/compass.md:85
msgid "`Embed.toml` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/compass.md:89
#, fuzzy
msgid ""
"```toml\n"
"[default.general]\n"
"chip = \"nrf52833_xxAA\"\n"
"\n"
"[debug.gdb]\n"
"enabled = true\n"
"\n"
"[debug.reset]\n"
"halt_afterwards = true\n"
"```"
msgstr ""
"```toml\n"
"[default.general]\n"
"chip = \"nrf52833_xxAA\"\n"
"\n"
"[debug.gdb]\n"
"enabled = true\n"
"```"
#: src/exercises/bare-metal/compass.md:100 src/exercises/bare-metal/rtc.md:985
msgid "`.cargo/config.toml` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/compass.md:104
msgid ""
"```toml\n"
"[build]\n"
"target = \"thumbv7em-none-eabihf\" # Cortex-M4F\n"
"\n"
"[target.'cfg(all(target_arch = \"arm\", target_os = \"none\"))']\n"
"rustflags = [\"-C\", \"link-arg=-Tlink.x\"]\n"
"```"
msgstr ""
#: src/exercises/bare-metal/compass.md:112
msgid "See the serial output on Linux with:"
msgstr ""
#: src/exercises/bare-metal/compass.md:114
msgid ""
"```sh\n"
"picocom --baud 115200 --imap lfcrlf /dev/ttyACM0\n"
"```"
msgstr ""
#: src/exercises/bare-metal/compass.md:118
msgid ""
"Or on Mac OS something like (the device name may be slightly different):"
msgstr ""
#: src/exercises/bare-metal/compass.md:120
msgid ""
"```sh\n"
"picocom --baud 115200 --imap lfcrlf /dev/tty.usbmodem14502\n"
"```"
msgstr ""
#: src/exercises/bare-metal/compass.md:124
msgid "Use Ctrl+A Ctrl+Q to quit picocom."
msgstr ""
#: src/bare-metal/aps.md:1
msgid "Application processors"
msgstr "애플리케이션 프로세서"
#: src/bare-metal/aps.md:3
msgid ""
"So far we've talked about microcontrollers, such as the Arm Cortex-M series. "
"Now let's try writing something for Cortex-A. For simplicity we'll just work "
"with QEMU's aarch64 ['virt'](https://qemu-project.gitlab.io/qemu/system/arm/"
"virt.html) board."
msgstr ""
"지금까지 Arm Cortex-M 시리즈와 같은 마이크로컨트롤러에 관해 알아봤습니다. 이"
"제 애플리케이션 프로세서인 Cortex-A를 위한 코드를 작성해 보겠습니다. 편의상 "
"QEMU의 aarch64 ['virt'](https://qemu-project.gitlab.io/qemu/system/arm/virt."
"html) 보드를 사용합니다."
#: src/bare-metal/aps.md:9
msgid ""
"Broadly speaking, microcontrollers don't have an MMU or multiple levels of "
"privilege (exception levels on Arm CPUs, rings on x86), while application "
"processors do."
msgstr ""
"일반적으로 마이크로컨트롤러에는 MMU 또는 다중 레벨 권한(Arm CPU에서는 익셉션 "
"레벨(exception level), x86에서는 링(ring))이 없습니다. 애플리케이션 프로세서"
"는 이들을 가지고 있습니다."
#: src/bare-metal/aps.md:11
msgid ""
"QEMU supports emulating various different machines or board models for each "
"architecture. The 'virt' board doesn't correspond to any particular real "
"hardware, but is designed purely for virtual machines."
msgstr ""
"QEMU는 아키텍처별로 다양한 머신 또는 보드 모델을 에뮬레이션할 수 있습니다. "
"'virt' 보드는 특정 실제 하드웨어를 에뮬레이션 하지 않으며, 가상 머신용으로만 "
"설계되었습니다."
#: src/bare-metal/aps/entry-point.md:3
msgid ""
"Before we can start running Rust code, we need to do some initialisation."
msgstr ""
#: src/bare-metal/aps/entry-point.md:5
msgid ""
"```armasm\n"
".section .init.entry, \"ax\"\n"
".global entry\n"
"entry:\n"
" /*\n"
" * Load and apply the memory management configuration, ready to enable "
"MMU and\n"
" * caches.\n"
" */\n"
" adrp x30, idmap\n"
" msr ttbr0_el1, x30\n"
"\n"
" mov_i x30, .Lmairval\n"
" msr mair_el1, x30\n"
"\n"
" mov_i x30, .Ltcrval\n"
" /* Copy the supported PA range into TCR_EL1.IPS. */\n"
" mrs x29, id_aa64mmfr0_el1\n"
" bfi x30, x29, #32, #4\n"
"\n"
" msr tcr_el1, x30\n"
"\n"
" mov_i x30, .Lsctlrval\n"
"\n"
" /*\n"
" * Ensure everything before this point has completed, then invalidate "
"any\n"
" * potentially stale local TLB entries before they start being used.\n"
" */\n"
" isb\n"
" tlbi vmalle1\n"
" ic iallu\n"
" dsb nsh\n"
" isb\n"
"\n"
" /*\n"
" * Configure sctlr_el1 to enable MMU and cache and don't proceed until "
"this\n"
" * has completed.\n"
" */\n"
" msr sctlr_el1, x30\n"
" isb\n"
"\n"
" /* Disable trapping floating point access in EL1. */\n"
" mrs x30, cpacr_el1\n"
" orr x30, x30, #(0x3 << 20)\n"
" msr cpacr_el1, x30\n"
" isb\n"
"\n"
" /* Zero out the bss section. */\n"
" adr_l x29, bss_begin\n"
" adr_l x30, bss_end\n"
"0: cmp x29, x30\n"
" b.hs 1f\n"
" stp xzr, xzr, [x29], #16\n"
" b 0b\n"
"\n"
"1: /* Prepare the stack. */\n"
" adr_l x30, boot_stack_end\n"
" mov sp, x30\n"
"\n"
" /* Set up exception vector. */\n"
" adr x30, vector_table_el1\n"
" msr vbar_el1, x30\n"
"\n"
" /* Call into Rust code. */\n"
" bl main\n"
"\n"
" /* Loop forever waiting for interrupts. */\n"
"2: wfi\n"
" b 2b\n"
"```"
msgstr ""
#: src/bare-metal/aps/entry-point.md:77
msgid ""
"This is the same as it would be for C: initialising the processor state, "
"zeroing the BSS, and setting up the stack pointer."
msgstr ""
#: src/bare-metal/aps/entry-point.md:79
msgid ""
"The BSS (block starting symbol, for historical reasons) is the part of the "
"object file which containing statically allocated variables which are "
"initialised to zero. They are omitted from the image, to avoid wasting space "
"on zeroes. The compiler assumes that the loader will take care of zeroing "
"them."
msgstr ""
#: src/bare-metal/aps/entry-point.md:83
msgid ""
"The BSS may already be zeroed, depending on how memory is initialised and "
"the image is loaded, but we zero it to be sure."
msgstr ""
#: src/bare-metal/aps/entry-point.md:85
msgid ""
"We need to enable the MMU and cache before reading or writing any memory. If "
"we don't:"
msgstr ""
#: src/bare-metal/aps/entry-point.md:86
msgid ""
"Unaligned accesses will fault. We build the Rust code for the `aarch64-"
"unknown-none` target which sets `+strict-align` to prevent the compiler "
"generating unaligned accesses, so it should be fine in this case, but this "
"is not necessarily the case in general."
msgstr ""
#: src/bare-metal/aps/entry-point.md:89
msgid ""
"If it were running in a VM, this can lead to cache coherency issues. The "
"problem is that the VM is accessing memory directly with the cache disabled, "
"while the host has cachable aliases to the same memory. Even if the host "
"doesn't explicitly access the memory, speculative accesses can lead to cache "
"fills, and then changes from one or the other will get lost when the cache "
"is cleaned or the VM enables the cache. (Cache is keyed by physical address, "
"not VA or IPA.)"
msgstr ""
#: src/bare-metal/aps/entry-point.md:94
msgid ""
"For simplicity, we just use a hardcoded pagetable (see `idmap.S`) which "
"identity maps the first 1 GiB of address space for devices, the next 1 GiB "
"for DRAM, and another 1 GiB higher up for more devices. This matches the "
"memory layout that QEMU uses."
msgstr ""
#: src/bare-metal/aps/entry-point.md:97
msgid ""
"We also set up the exception vector (`vbar_el1`), which we'll see more about "
"later."
msgstr ""
#: src/bare-metal/aps/entry-point.md:98
msgid ""
"All examples this afternoon assume we will be running at exception level 1 "
"(EL1). If you need to run at a different exception level you'll need to "
"modify `entry.S` accordingly."
msgstr ""
#: src/bare-metal/aps/inline-assembly.md:1
msgid "Inline assembly"
msgstr "인라인 어셈블리"
#: src/bare-metal/aps/inline-assembly.md:3
msgid ""
"Sometimes we need to use assembly to do things that aren't possible with "
"Rust code. For example, to make an "
msgstr ""
"가끔 Rust 코드로는 구현이 불가능한 작업들이 있으며, 이 경우 어셈블리를 사용해"
"야 합니다. 예를 들어 펌웨어를 향해서 시스템 전원을 끄라고 "
#: src/bare-metal/aps/inline-assembly.md:4
msgid "HVC"
msgstr "HVC"
#: src/bare-metal/aps/inline-assembly.md:4
msgid " to tell the firmware to power off the system:"
msgstr "를 호출하는 방법은 다음과 같습니다."
#: src/bare-metal/aps/inline-assembly.md:6
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"use core::arch::asm;\n"
"use core::panic::PanicInfo;\n"
"\n"
"mod exceptions;\n"
"\n"
"const PSCI_SYSTEM_OFF: u32 = 0x84000008;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {\n"
" // Safe because this only uses the declared registers and doesn't do\n"
" // anything with memory.\n"
" unsafe {\n"
" asm!(\"hvc #0\",\n"
" inout(\"w0\") PSCI_SYSTEM_OFF => _,\n"
" inout(\"w1\") 0 => _,\n"
" inout(\"w2\") 0 => _,\n"
" inout(\"w3\") 0 => _,\n"
" inout(\"w4\") 0 => _,\n"
" inout(\"w5\") 0 => _,\n"
" inout(\"w6\") 0 => _,\n"
" inout(\"w7\") 0 => _,\n"
" options(nomem, nostack)\n"
" );\n"
" }\n"
"\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"use core::arch::asm;\n"
"use core::panic::PanicInfo;\n"
"\n"
"mod exceptions;\n"
"\n"
"const PSCI_SYSTEM_OFF: u32 = 0x84000008;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn main(_x0: u64, _x1: u64, _x2: u64, _x3: u64) {\n"
" // Safe because this only uses the declared registers and doesn't do\n"
" // anything with memory.\n"
" unsafe {\n"
" asm!(\"hvc #0\",\n"
" inout(\"w0\") PSCI_SYSTEM_OFF => _,\n"
" inout(\"w1\") 0 => _,\n"
" inout(\"w2\") 0 => _,\n"
" inout(\"w3\") 0 => _,\n"
" inout(\"w4\") 0 => _,\n"
" inout(\"w5\") 0 => _,\n"
" inout(\"w6\") 0 => _,\n"
" inout(\"w7\") 0 => _,\n"
" options(nomem, nostack)\n"
" );\n"
" }\n"
"\n"
" loop {}\n"
"}\n"
"```"
#: src/bare-metal/aps/inline-assembly.md:39
msgid ""
"(If you actually want to do this, use the [`smccc`](https://crates.io/crates/"
"smccc) crate which has wrappers for all these functions.)"
msgstr ""
"실제로 이를 실행하려면 이러한 모든 함수를 위한 래퍼가 포함된 [`smccc`]"
"(https://crates.io/crates/smccc) 크레이트를 사용하세요."
#: src/bare-metal/aps/inline-assembly.md:43
msgid ""
"PSCI is the Arm Power State Coordination Interface, a standard set of "
"functions to manage system and CPU power states, among other things. It is "
"implemented by EL3 firmware and hypervisors on many systems."
msgstr ""
"PSCI (Power State Coordination Interface)는 시스템 및 CPU 전원 상태를 관리하"
"는 Arm의 표준 인터페이스입니다. 이 인터페이스는 EL3 펌웨어와 하이퍼바이저에 "
"의해 구현됩니다."
#: src/bare-metal/aps/inline-assembly.md:46
msgid ""
"The `0 => _` syntax means initialise the register to 0 before running the "
"inline assembly code, and ignore its contents afterwards. We need to use "
"`inout` rather than `in` because the call could potentially clobber the "
"contents of the registers."
msgstr ""
"`0 => _` 문법은 인라인 어셈블리 코드를 실행하기 전에 레지스터를 0으로 초기화"
"하고 그 후에는 그 레지스터의 값을 무시함을 의미합니다. 호출 시 레지스터의 값"
"이 덮어 써질 수 있으므로 `in` 대신 `inout`을 사용해야 합니다."
#: src/bare-metal/aps/inline-assembly.md:49
msgid ""
"This `main` function needs to be `#[no_mangle]` and `extern \"C\"` because "
"it is called from our entry point in `entry.S`."
msgstr ""
"이 `main` 함수는 `#[no_mangle]` 및 `extern \"C\"`여야 합니다. 왜냐하면 이 함"
"수는 Rust 코드가 아닌, 어셈블러로 작성된 `entry.S`에서 호출되기 때문입니다."
#: src/bare-metal/aps/inline-assembly.md:51
msgid ""
"`_x0`–`_x3` are the values of registers `x0`–`x3`, which are conventionally "
"used by the bootloader to pass things like a pointer to the device tree. "
"According to the standard aarch64 calling convention (which is what `extern "
"\"C\"` specifies to use), registers `x0`–`x7` are used for the first 8 "
"arguments passed to a function, so `entry.S` doesn't need to do anything "
"special except make sure it doesn't change these registers."
msgstr ""
"`_x0`–`_x3`는 `x0`에서 `x3` 레지스터들의 값입니다. 이 레지스터들은 일반적으"
"로 부트로더에서 디바이스 트리에 대한 포인터 등을 전달할 때 사용됩니다. 표준 "
"aarch64 호출 규약(`extern \"C\"`에서 사용하도록 지정)에 따라 레지스터 `x0`에"
"서 `x7`이 함수에 전달된 처음 8개 인수에 사용되므로 `entry.S`는 이러한 레지스"
"터를 변경하지 않는지 확인하는 것 외에는 특별히 할 작업이 없습니다."
#: src/bare-metal/aps/inline-assembly.md:56
msgid ""
"Run the example in QEMU with `make qemu_psci` under `src/bare-metal/aps/"
"examples`."
msgstr ""
"`src/bare-metal/aps/examples`에서 `make qemu_psci`를 사용하여 QEMU에서 예시"
"를 실행합니다."
#: src/bare-metal/aps/mmio.md:1
msgid "Volatile memory access for MMIO"
msgstr "MMIO를 위한 휘발성(volatile) 메모리 액세스"
#: src/bare-metal/aps/mmio.md:3
msgid "Use `pointer::read_volatile` and `pointer::write_volatile`."
msgstr "`pointer::read_volatile` 및 `pointer::write_volatile`을 사용하세요."
#: src/bare-metal/aps/mmio.md:4
msgid "Never hold a reference."
msgstr "참조를 유지하지 마세요."
#: src/bare-metal/aps/mmio.md:5
msgid ""
"`addr_of!` lets you get fields of structs without creating an intermediate "
"reference."
msgstr ""
"`addr_of!`를 사용하면 임시 용도의 참조를 만들지 않고도 구조체 필드를 가져올 "
"수 있습니다."
#: src/bare-metal/aps/mmio.md:9
msgid ""
"Volatile access: read or write operations may have side-effects, so prevent "
"the compiler or hardware from reordering, duplicating or eliding them."
msgstr ""
"휘발성(volatile) 액세스: 읽기 또는 쓰기 작업이 부수 효과(side effect)를 동반"
"할 수 있기 때문에 컴파일러나 하드웨어가 임의로 이를 읽기 쓰기 작업의 순서를 "
"바꾸거나, 중복해서 수행하거나 또는 제거하지 못하게 합니다."
#: src/bare-metal/aps/mmio.md:11
msgid ""
"Usually if you write and then read, e.g. via a mutable reference, the "
"compiler may assume that the value read is the same as the value just "
"written, and not bother actually reading memory."
msgstr ""
"일반적으로 쓰고 난 후 읽으면(예: 변경 가능한 참조를 통해) 컴파일러는 읽은 값"
"이 방금 쓴 값과 동일하다고 가정하고 실제로 메모리를 읽지 않을 수 있습니다."
#: src/bare-metal/aps/mmio.md:13
msgid ""
"Some existing crates for volatile access to hardware do hold references, but "
"this is unsound. Whenever a reference exist, the compiler may choose to "
"dereference it."
msgstr ""
"하드웨어에 대한 휘발성 액세스를 위한 일부 기존 크레이트는 참조를 유지하지만 "
"이는 올바른 것이 아닙니다. 참조가 있을 때마다 컴파일러는 이를 역참조하도록 선"
"택할 수 있습니다."
#: src/bare-metal/aps/mmio.md:15
msgid ""
"Use the `addr_of!` macro to get struct field pointers from a pointer to the "
"struct."
msgstr ""
"`addr_of!` 매크로를 사용하여 구조체 포인터에서 구조체 필드 포인터를 가져옵니"
"다."
#: src/bare-metal/aps/uart.md:1
msgid "Let's write a UART driver"
msgstr "UART 드라이버 작성"
#: src/bare-metal/aps/uart.md:3
msgid ""
"The QEMU 'virt' machine has a [PL011](https://developer.arm.com/"
"documentation/ddi0183/g) UART, so let's write a driver for that."
msgstr ""
"QEMU의 'virt' 보드에는 [PL011](https://developer.arm.com/documentation/"
"ddi0183/g) UART가 있으므로 이를 위한 드라이버를 작성해 보겠습니다."
#: src/bare-metal/aps/uart.md:5
msgid ""
"```rust,editable\n"
"const FLAG_REGISTER_OFFSET: usize = 0x18;\n"
"const FR_BUSY: u8 = 1 << 3;\n"
"const FR_TXFF: u8 = 1 << 5;\n"
"\n"
"/// Minimal driver for a PL011 UART.\n"
"#[derive(Debug)]\n"
"pub struct Uart {\n"
" base_address: *mut u8,\n"
"}\n"
"\n"
"impl Uart {\n"
" /// Constructs a new instance of the UART driver for a PL011 device at "
"the\n"
" /// given base address.\n"
" ///\n"
" /// # Safety\n"
" ///\n"
" /// The given base address must point to the 8 MMIO control registers of "
"a\n"
" /// PL011 device, which must be mapped into the address space of the "
"process\n"
" /// as device memory and not have any other aliases.\n"
" pub unsafe fn new(base_address: *mut u8) -> Self {\n"
" Self { base_address }\n"
" }\n"
"\n"
" /// Writes a single byte to the UART.\n"
" pub fn write_byte(&self, byte: u8) {\n"
" // Wait until there is room in the TX buffer.\n"
" while self.read_flag_register() & FR_TXFF != 0 {}\n"
"\n"
" // Safe because we know that the base address points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe {\n"
" // Write to the TX buffer.\n"
" self.base_address.write_volatile(byte);\n"
" }\n"
"\n"
" // Wait until the UART is no longer busy.\n"
" while self.read_flag_register() & FR_BUSY != 0 {}\n"
" }\n"
"\n"
" fn read_flag_register(&self) -> u8 {\n"
" // Safe because we know that the base address points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe { self.base_address.add(FLAG_REGISTER_OFFSET)."
"read_volatile() }\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"const FLAG_REGISTER_OFFSET: usize = 0x18;\n"
"const FR_BUSY: u8 = 1 << 3;\n"
"const FR_TXFF: u8 = 1 << 5;\n"
"\n"
"/// PL011 UART용 최소 드라이버입니다.\n"
"#[derive(Debug)]\n"
"pub struct Uart {\n"
" base_address: *mut u8,\n"
"}\n"
"\n"
"impl Uart {\n"
" /// Constructs a new instance of the UART driver for a PL011 device at "
"the\n"
" /// given base address.\n"
" ///\n"
" /// # Safety\n"
" ///\n"
" /// The given base address must point to the 8 MMIO control registers of "
"a\n"
" /// PL011 device, which must be mapped into the address space of the "
"process\n"
" /// as device memory and not have any other aliases.\n"
" pub unsafe fn new(base_address: *mut u8) -> Self {\n"
" Self { base_address }\n"
" }\n"
"\n"
" /// UART에 한 바이트를 씁니다.\n"
" pub fn write_byte(&self, byte: u8) {\n"
" // Wait until there is room in the TX buffer.\n"
" while self.read_flag_register() & FR_TXFF != 0 {}\n"
"\n"
" // `base_address`가 PL011의 컨트롤 레지스터가 매핑된 주소를 가리키"
"고\n"
" // 있으므로 안전합니다.\n"
" unsafe {\n"
" // Write to the TX buffer.\n"
" self.base_address.write_volatile(byte);\n"
" }\n"
"\n"
" // UART가 더 이상 사용 중이 아닐 때까지 기다립니다.\n"
" while self.read_flag_register() & FR_BUSY != 0 {}\n"
" }\n"
"\n"
" fn read_flag_register(&self) -> u8 {\n"
" // Safe because we know that the base address points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe { self.base_address.add(FLAG_REGISTER_OFFSET)."
"read_volatile() }\n"
" }\n"
"}\n"
"```"
#: src/bare-metal/aps/uart.md:55
msgid ""
"Note that `Uart::new` is unsafe while the other methods are safe. This is "
"because as long as the caller of `Uart::new` guarantees that its safety "
"requirements are met (i.e. that there is only ever one instance of the "
"driver for a given UART, and nothing else aliasing its address space), then "
"it is always safe to call `write_byte` later because we can assume the "
"necessary preconditions."
msgstr ""
"`Uart::new`는 안전하지 않지만(usafe), 그 외 다른 메서드들은 안전한(safe) 점"
"에 주목하세요.다른 메서드들이 안전할 수 있는 이유는, `Uart::new`의 안전 요구"
"사항(즉, 지정된 UART의 드라이버 인스턴스가 하나만 있으며 주소 공간에 별칭을 "
"지정하는 다른 항목이 없음) 이 만족되기만 하면 `write_byte`와 같은 함수를 안전"
"하게 호출하는데 있어서 필요한 모든 전제조건이 만족되기 때문입니다."
#: src/bare-metal/aps/uart.md:60
msgid ""
"We could have done it the other way around (making `new` safe but "
"`write_byte` unsafe), but that would be much less convenient to use as every "
"place that calls `write_byte` would need to reason about the safety"
msgstr ""
"반대 방법으로도 실행할 수 있지만(`new`를 안전하게 만들고 `write_byte`를 안전"
"하지 않게 만듦) 이는 `write_byte`를 호출하는 모든 위치에서 안전성에 관해 추론"
"해야 하므로 사용 편의성이 훨씬 떨어집니다."
#: src/bare-metal/aps/uart.md:63
msgid ""
"This is a common pattern for writing safe wrappers of unsafe code: moving "
"the burden of proof for soundness from a large number of places to a smaller "
"number of places."
msgstr ""
"이는 안전하지 않은 코드의 안전한 래퍼를 작성하는 일반적인 패턴입니다. 안전에 "
"관한 증명 부담을 여러 많은 위치에서 소수의 위치로 옮기는 것입니다."
#: src/bare-metal/aps/uart/traits.md:1
#, fuzzy
msgid "More traits"
msgstr "트레잇(Trait)"
#: src/bare-metal/aps/uart/traits.md:3
msgid ""
"We derived the `Debug` trait. It would be useful to implement a few more "
"traits too."
msgstr ""
#: src/bare-metal/aps/uart/traits.md:5
msgid ""
"```rust,editable,compile_fail\n"
"use core::fmt::{self, Write};\n"
"\n"
"impl Write for Uart {\n"
" fn write_str(&mut self, s: &str) -> fmt::Result {\n"
" for c in s.as_bytes() {\n"
" self.write_byte(*c);\n"
" }\n"
" Ok(())\n"
" }\n"
"}\n"
"\n"
"// Safe because it just contains a pointer to device memory, which can be\n"
"// accessed from any context.\n"
"unsafe impl Send for Uart {}\n"
"```"
msgstr ""
#: src/bare-metal/aps/uart/traits.md:24
msgid ""
"Implementing `Write` lets us use the `write!` and `writeln!` macros with our "
"`Uart` type."
msgstr ""
#: src/bare-metal/aps/uart/traits.md:25
msgid ""
"Run the example in QEMU with `make qemu_minimal` under `src/bare-metal/aps/"
"examples`."
msgstr ""
#: src/bare-metal/aps/better-uart.md:1
msgid "A better UART driver"
msgstr "더 나은 UART 드라이버"
#: src/bare-metal/aps/better-uart.md:3
msgid ""
"The PL011 actually has [a bunch more registers](https://developer.arm.com/"
"documentation/ddi0183/g/programmers-model/summary-of-registers), and adding "
"offsets to construct pointers to access them is error-prone and hard to "
"read. Plus, some of them are bit fields which would be nice to access in a "
"structured way."
msgstr ""
"PL011에는 실제로 [훨씬 더 많은 레지스터](https://developer.arm.com/"
"documentation/ddi0183/g/programmers-model/summary-of-registers)가 있으며, 이"
"에 액세스할 포인터를 구성하기 위해 오프셋을 추가하면 오류가 발생하기 쉽고 읽"
"기 어렵습니다. 또한 그중 일부는 구조화된 방식으로 액세스할 수 있는 비트 필드"
"입니다."
#: src/bare-metal/aps/better-uart.md:7
msgid "Offset"
msgstr "오프셋"
#: src/bare-metal/aps/better-uart.md:7
msgid "Register name"
msgstr "레지스터 이름"
#: src/bare-metal/aps/better-uart.md:7
msgid "Width"
msgstr "너비"
#: src/bare-metal/aps/better-uart.md:9
msgid "0x00"
msgstr "0x00"
#: src/bare-metal/aps/better-uart.md:9
msgid "DR"
msgstr "DR"
#: src/bare-metal/aps/better-uart.md:9
msgid "12"
msgstr "12"
#: src/bare-metal/aps/better-uart.md:10
msgid "0x04"
msgstr "0x04"
#: src/bare-metal/aps/better-uart.md:10
msgid "RSR"
msgstr "RSR"
#: src/bare-metal/aps/better-uart.md:10
msgid "4"
msgstr "4"
#: src/bare-metal/aps/better-uart.md:11
msgid "0x18"
msgstr "0x18"
#: src/bare-metal/aps/better-uart.md:11
msgid "FR"
msgstr "FR"
#: src/bare-metal/aps/better-uart.md:11
msgid "9"
msgstr "9"
#: src/bare-metal/aps/better-uart.md:12
msgid "0x20"
msgstr "0x20"
#: src/bare-metal/aps/better-uart.md:12
msgid "ILPR"
msgstr "ILPR"
#: src/bare-metal/aps/better-uart.md:12 src/bare-metal/aps/better-uart.md:15
msgid "8"
msgstr "8"
#: src/bare-metal/aps/better-uart.md:13
msgid "0x24"
msgstr "0x24"
#: src/bare-metal/aps/better-uart.md:13
msgid "IBRD"
msgstr "IBRD"
#: src/bare-metal/aps/better-uart.md:13 src/bare-metal/aps/better-uart.md:16
msgid "16"
msgstr "16"
#: src/bare-metal/aps/better-uart.md:14
msgid "0x28"
msgstr "0x28"
#: src/bare-metal/aps/better-uart.md:14
msgid "FBRD"
msgstr "FBRD"
#: src/bare-metal/aps/better-uart.md:14 src/bare-metal/aps/better-uart.md:17
msgid "6"
msgstr "6"
#: src/bare-metal/aps/better-uart.md:15
msgid "0x2c"
msgstr "0x2c"
#: src/bare-metal/aps/better-uart.md:15
msgid "LCR_H"
msgstr "LCR_H"
#: src/bare-metal/aps/better-uart.md:16
msgid "0x30"
msgstr "0x30"
#: src/bare-metal/aps/better-uart.md:16
msgid "CR"
msgstr "CR"
#: src/bare-metal/aps/better-uart.md:17
msgid "0x34"
msgstr "0x34"
#: src/bare-metal/aps/better-uart.md:17
msgid "IFLS"
msgstr "IFLS"
#: src/bare-metal/aps/better-uart.md:18
msgid "0x38"
msgstr "0x38"
#: src/bare-metal/aps/better-uart.md:18
msgid "IMSC"
msgstr "IMSC"
#: src/bare-metal/aps/better-uart.md:18 src/bare-metal/aps/better-uart.md:19
#: src/bare-metal/aps/better-uart.md:20 src/bare-metal/aps/better-uart.md:21
msgid "11"
msgstr "11"
#: src/bare-metal/aps/better-uart.md:19
msgid "0x3c"
msgstr "0x3c"
#: src/bare-metal/aps/better-uart.md:19
msgid "RIS"
msgstr "RIS"
#: src/bare-metal/aps/better-uart.md:20
msgid "0x40"
msgstr "0x40"
#: src/bare-metal/aps/better-uart.md:20
msgid "MIS"
msgstr "MIS"
#: src/bare-metal/aps/better-uart.md:21
msgid "0x44"
msgstr "0x44"
#: src/bare-metal/aps/better-uart.md:21
msgid "ICR"
msgstr "ICR"
#: src/bare-metal/aps/better-uart.md:22
msgid "0x48"
msgstr "0x48"
#: src/bare-metal/aps/better-uart.md:22
msgid "DMACR"
msgstr "DMACR"
#: src/bare-metal/aps/better-uart.md:22
msgid "3"
msgstr "3"
#: src/bare-metal/aps/better-uart.md:26
msgid "There are also some ID registers which have been omitted for brevity."
msgstr "간결성을 위해 일부 ID 레지스터는 생략되었습니다."
#: src/bare-metal/aps/better-uart/bitflags.md:3
msgid ""
"The [`bitflags`](https://crates.io/crates/bitflags) crate is useful for "
"working with bitflags."
msgstr ""
#: src/bare-metal/aps/better-uart/bitflags.md:5
msgid ""
"```rust,editable,compile_fail\n"
"use bitflags::bitflags;\n"
"\n"
"bitflags! {\n"
" /// Flags from the UART flag register.\n"
" #[repr(transparent)]\n"
" #[derive(Copy, Clone, Debug, Eq, PartialEq)]\n"
" struct Flags: u16 {\n"
" /// Clear to send.\n"
" const CTS = 1 << 0;\n"
" /// Data set ready.\n"
" const DSR = 1 << 1;\n"
" /// Data carrier detect.\n"
" const DCD = 1 << 2;\n"
" /// UART busy transmitting data.\n"
" const BUSY = 1 << 3;\n"
" /// Receive FIFO is empty.\n"
" const RXFE = 1 << 4;\n"
" /// Transmit FIFO is full.\n"
" const TXFF = 1 << 5;\n"
" /// Receive FIFO is full.\n"
" const RXFF = 1 << 6;\n"
" /// Transmit FIFO is empty.\n"
" const TXFE = 1 << 7;\n"
" /// Ring indicator.\n"
" const RI = 1 << 8;\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/bare-metal/aps/better-uart/bitflags.md:37
msgid ""
"The `bitflags!` macro creates a newtype something like `Flags(u16)`, along "
"with a bunch of method implementations to get and set flags."
msgstr ""
#: src/bare-metal/aps/better-uart/registers.md:1
#, fuzzy
msgid "Multiple registers"
msgstr "더 많은 레지스터"
#: src/bare-metal/aps/better-uart/registers.md:3
msgid ""
"We can use a struct to represent the memory layout of the UART's registers."
msgstr ""
#: src/bare-metal/aps/better-uart/registers.md:5
msgid ""
"```rust,editable,compile_fail\n"
"#[repr(C, align(4))]\n"
"struct Registers {\n"
" dr: u16,\n"
" _reserved0: [u8; 2],\n"
" rsr: ReceiveStatus,\n"
" _reserved1: [u8; 19],\n"
" fr: Flags,\n"
" _reserved2: [u8; 6],\n"
" ilpr: u8,\n"
" _reserved3: [u8; 3],\n"
" ibrd: u16,\n"
" _reserved4: [u8; 2],\n"
" fbrd: u8,\n"
" _reserved5: [u8; 3],\n"
" lcr_h: u8,\n"
" _reserved6: [u8; 3],\n"
" cr: u16,\n"
" _reserved7: [u8; 3],\n"
" ifls: u8,\n"
" _reserved8: [u8; 3],\n"
" imsc: u16,\n"
" _reserved9: [u8; 2],\n"
" ris: u16,\n"
" _reserved10: [u8; 2],\n"
" mis: u16,\n"
" _reserved11: [u8; 2],\n"
" icr: u16,\n"
" _reserved12: [u8; 2],\n"
" dmacr: u8,\n"
" _reserved13: [u8; 3],\n"
"}\n"
"```"
msgstr ""
#: src/bare-metal/aps/better-uart/registers.md:41
msgid ""
"[`#[repr(C)]`](https://doc.rust-lang.org/reference/type-layout.html#the-c-"
"representation) tells the compiler to lay the struct fields out in order, "
"following the same rules as C. This is necessary for our struct to have a "
"predictable layout, as default Rust representation allows the compiler to "
"(among other things) reorder fields however it sees fit."
msgstr ""
#: src/bare-metal/aps/better-uart/driver.md:3
msgid "Now let's use the new `Registers` struct in our driver."
msgstr ""
#: src/bare-metal/aps/better-uart/driver.md:5
#, fuzzy
msgid ""
"```rust,editable,compile_fail\n"
"/// Driver for a PL011 UART.\n"
"#[derive(Debug)]\n"
"pub struct Uart {\n"
" registers: *mut Registers,\n"
"}\n"
"\n"
"impl Uart {\n"
" /// Constructs a new instance of the UART driver for a PL011 device at "
"the\n"
" /// given base address.\n"
" ///\n"
" /// # Safety\n"
" ///\n"
" /// The given base address must point to the 8 MMIO control registers of "
"a\n"
" /// PL011 device, which must be mapped into the address space of the "
"process\n"
" /// as device memory and not have any other aliases.\n"
" pub unsafe fn new(base_address: *mut u32) -> Self {\n"
" Self {\n"
" registers: base_address as *mut Registers,\n"
" }\n"
" }\n"
"\n"
" /// Writes a single byte to the UART.\n"
" pub fn write_byte(&self, byte: u8) {\n"
" // Wait until there is room in the TX buffer.\n"
" while self.read_flag_register().contains(Flags::TXFF) {}\n"
"\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe {\n"
" // Write to the TX buffer.\n"
" addr_of_mut!((*self.registers).dr).write_volatile(byte.into());\n"
" }\n"
"\n"
" // Wait until the UART is no longer busy.\n"
" while self.read_flag_register().contains(Flags::BUSY) {}\n"
" }\n"
"\n"
" /// Reads and returns a pending byte, or `None` if nothing has been "
"received.\n"
" pub fn read_byte(&self) -> Option<u8> {\n"
" if self.read_flag_register().contains(Flags::RXFE) {\n"
" None\n"
" } else {\n"
" let data = unsafe { addr_of!((*self.registers).dr)."
"read_volatile() };\n"
" // TODO: Check for error conditions in bits 8-11.\n"
" Some(data as u8)\n"
" }\n"
" }\n"
"\n"
" fn read_flag_register(&self) -> Flags {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe { addr_of!((*self.registers).fr).read_volatile() }\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"const FLAG_REGISTER_OFFSET: usize = 0x18;\n"
"const FR_BUSY: u8 = 1 << 3;\n"
"const FR_TXFF: u8 = 1 << 5;\n"
"\n"
"/// PL011 UART용 최소 드라이버입니다.\n"
"#[derive(Debug)]\n"
"pub struct Uart {\n"
" base_address: *mut u8,\n"
"}\n"
"\n"
"impl Uart {\n"
" /// Constructs a new instance of the UART driver for a PL011 device at "
"the\n"
" /// given base address.\n"
" ///\n"
" /// # Safety\n"
" ///\n"
" /// The given base address must point to the 8 MMIO control registers of "
"a\n"
" /// PL011 device, which must be mapped into the address space of the "
"process\n"
" /// as device memory and not have any other aliases.\n"
" pub unsafe fn new(base_address: *mut u8) -> Self {\n"
" Self { base_address }\n"
" }\n"
"\n"
" /// UART에 한 바이트를 씁니다.\n"
" pub fn write_byte(&self, byte: u8) {\n"
" // Wait until there is room in the TX buffer.\n"
" while self.read_flag_register() & FR_TXFF != 0 {}\n"
"\n"
" // `base_address`가 PL011의 컨트롤 레지스터가 매핑된 주소를 가리키"
"고\n"
" // 있으므로 안전합니다.\n"
" unsafe {\n"
" // Write to the TX buffer.\n"
" self.base_address.write_volatile(byte);\n"
" }\n"
"\n"
" // UART가 더 이상 사용 중이 아닐 때까지 기다립니다.\n"
" while self.read_flag_register() & FR_BUSY != 0 {}\n"
" }\n"
"\n"
" fn read_flag_register(&self) -> u8 {\n"
" // Safe because we know that the base address points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe { self.base_address.add(FLAG_REGISTER_OFFSET)."
"read_volatile() }\n"
" }\n"
"}\n"
"```"
#: src/bare-metal/aps/better-uart/driver.md:64
msgid ""
"Note the use of `addr_of!` / `addr_of_mut!` to get pointers to individual "
"fields without creating an intermediate reference, which would be unsound."
msgstr ""
#: src/bare-metal/aps/better-uart/using.md:1
#: src/bare-metal/aps/logging/using.md:1
#, fuzzy
msgid "Using it"
msgstr "Bindgen 사용하기"
#: src/bare-metal/aps/better-uart/using.md:3
msgid ""
"Let's write a small program using our driver to write to the serial console, "
"and echo incoming bytes."
msgstr ""
#: src/bare-metal/aps/better-uart/using.md:6
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"mod exceptions;\n"
"mod pl011;\n"
"\n"
"use crate::pl011::Uart;\n"
"use core::fmt::Write;\n"
"use core::panic::PanicInfo;\n"
"use log::error;\n"
"use smccc::psci::system_off;\n"
"use smccc::Hvc;\n"
"\n"
"/// Base address of the primary PL011 UART.\n"
"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n"
" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 "
"device,\n"
" // and nothing else accesses that address range.\n"
" let mut uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n"
"\n"
" writeln!(uart, \"main({x0:#x}, {x1:#x}, {x2:#x}, {x3:#x})\").unwrap();\n"
"\n"
" loop {\n"
" if let Some(byte) = uart.read_byte() {\n"
" uart.write_byte(byte);\n"
" match byte {\n"
" b'\\r' => {\n"
" uart.write_byte(b'\\n');\n"
" }\n"
" b'q' => break,\n"
" _ => {}\n"
" }\n"
" }\n"
" }\n"
"\n"
" writeln!(uart, \"Bye!\").unwrap();\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"```"
msgstr ""
#: src/bare-metal/aps/better-uart/using.md:51
msgid ""
"As in the [inline assembly](../inline-assembly.md) example, this `main` "
"function is called from our entry point code in `entry.S`. See the speaker "
"notes there for details."
msgstr ""
#: src/bare-metal/aps/better-uart/using.md:53
msgid ""
"Run the example in QEMU with `make qemu` under `src/bare-metal/aps/examples`."
msgstr ""
#: src/bare-metal/aps/logging.md:3
msgid ""
"It would be nice to be able to use the logging macros from the [`log`]"
"(https://crates.io/crates/log) crate. We can do this by implementing the "
"`Log` trait."
msgstr ""
"[`log`](https://crates.io/crates/log) 크레이트의 로깅 매크로를 사용할 수 있으"
"면 좋습니다. 이는 `Log` 트레잇을 구현하면 됩니다."
#: src/bare-metal/aps/logging.md:6
msgid ""
"```rust,editable,compile_fail\n"
"use crate::pl011::Uart;\n"
"use core::fmt::Write;\n"
"use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};\n"
"use spin::mutex::SpinMutex;\n"
"\n"
"static LOGGER: Logger = Logger {\n"
" uart: SpinMutex::new(None),\n"
"};\n"
"\n"
"struct Logger {\n"
" uart: SpinMutex<Option<Uart>>,\n"
"}\n"
"\n"
"impl Log for Logger {\n"
" fn enabled(&self, _metadata: &Metadata) -> bool {\n"
" true\n"
" }\n"
"\n"
" fn log(&self, record: &Record) {\n"
" writeln!(\n"
" self.uart.lock().as_mut().unwrap(),\n"
" \"[{}] {}\",\n"
" record.level(),\n"
" record.args()\n"
" )\n"
" .unwrap();\n"
" }\n"
"\n"
" fn flush(&self) {}\n"
"}\n"
"\n"
"/// Initialises UART logger.\n"
"pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), "
"SetLoggerError> {\n"
" LOGGER.uart.lock().replace(uart);\n"
"\n"
" log::set_logger(&LOGGER)?;\n"
" log::set_max_level(max_level);\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use crate::pl011::Uart;\n"
"use core::fmt::Write;\n"
"use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};\n"
"use spin::mutex::SpinMutex;\n"
"\n"
"static LOGGER: Logger = Logger {\n"
" uart: SpinMutex::new(None),\n"
"};\n"
"\n"
"struct Logger {\n"
" uart: SpinMutex<Option<Uart>>,\n"
"}\n"
"\n"
"impl Log for Logger {\n"
" fn enabled(&self, _metadata: &Metadata) -> bool {\n"
" true\n"
" }\n"
"\n"
" fn log(&self, record: &Record) {\n"
" writeln!(\n"
" self.uart.lock().as_mut().unwrap(),\n"
" \"[{}] {}\",\n"
" record.level(),\n"
" record.args()\n"
" )\n"
" .unwrap();\n"
" }\n"
"\n"
" fn flush(&self) {}\n"
"}\n"
"\n"
"/// UART 로거를 초기화합니다.\n"
"pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), "
"SetLoggerError> {\n"
" LOGGER.uart.lock().replace(uart);\n"
"\n"
" log::set_logger(&LOGGER)?;\n"
" log::set_max_level(max_level);\n"
" Ok(())\n"
"}\n"
"```"
#: src/bare-metal/aps/logging.md:50
msgid ""
"The unwrap in `log` is safe because we initialise `LOGGER` before calling "
"`set_logger`."
msgstr ""
"`log`함수 안에서 `unwrap`하는 것은 괜찮습니다.. 왜냐하면 `set_logger`를 호출"
"하기 전에 `LOGGER`를 초기화하기 때문입니다."
#: src/bare-metal/aps/logging/using.md:3
msgid "We need to initialise the logger before we use it."
msgstr ""
#: src/bare-metal/aps/logging/using.md:5
msgid ""
"```rust,editable,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"mod exceptions;\n"
"mod logger;\n"
"mod pl011;\n"
"\n"
"use crate::pl011::Uart;\n"
"use core::panic::PanicInfo;\n"
"use log::{error, info, LevelFilter};\n"
"use smccc::psci::system_off;\n"
"use smccc::Hvc;\n"
"\n"
"/// Base address of the primary PL011 UART.\n"
"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n"
" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 "
"device,\n"
" // and nothing else accesses that address range.\n"
" let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n"
" logger::init(uart, LevelFilter::Trace).unwrap();\n"
"\n"
" info!(\"main({x0:#x}, {x1:#x}, {x2:#x}, {x3:#x})\");\n"
"\n"
" assert_eq!(x1, 42);\n"
"\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[panic_handler]\n"
"fn panic(info: &PanicInfo) -> ! {\n"
" error!(\"{info}\");\n"
" system_off::<Hvc>().unwrap();\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
#: src/bare-metal/aps/logging/using.md:46
msgid "Note that our panic handler can now log details of panics."
msgstr ""
#: src/bare-metal/aps/logging/using.md:47
msgid ""
"Run the example in QEMU with `make qemu_logger` under `src/bare-metal/aps/"
"examples`."
msgstr ""
#: src/bare-metal/aps/exceptions.md:3
msgid ""
"AArch64 defines an exception vector table with 16 entries, for 4 types of "
"exceptions (synchronous, IRQ, FIQ, SError) from 4 states (current EL with "
"SP0, current EL with SPx, lower EL using AArch64, lower EL using AArch32). "
"We implement this in assembly to save volatile registers to the stack before "
"calling into Rust code:"
msgstr ""
#: src/bare-metal/aps/exceptions.md:8
msgid ""
"```rust,editable,compile_fail\n"
"use log::error;\n"
"use smccc::psci::system_off;\n"
"use smccc::Hvc;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn sync_exception_current(_elr: u64, _spsr: u64) {\n"
" error!(\"sync_exception_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn irq_current(_elr: u64, _spsr: u64) {\n"
" error!(\"irq_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn fiq_current(_elr: u64, _spsr: u64) {\n"
" error!(\"fiq_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn serr_current(_elr: u64, _spsr: u64) {\n"
" error!(\"serr_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn sync_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"sync_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn irq_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"irq_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn fiq_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"fiq_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn serr_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"serr_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"```"
msgstr ""
#: src/bare-metal/aps/exceptions.md:64
msgid "EL is exception level; all our examples this afternoon run in EL1."
msgstr ""
#: src/bare-metal/aps/exceptions.md:65
msgid ""
"For simplicity we aren't distinguishing between SP0 and SPx for the current "
"EL exceptions, or between AArch32 and AArch64 for the lower EL exceptions."
msgstr ""
#: src/bare-metal/aps/exceptions.md:67
msgid ""
"For this example we just log the exception and power down, as we don't "
"expect any of them to actually happen."
msgstr ""
#: src/bare-metal/aps/exceptions.md:69
msgid ""
"We can think of exception handlers and our main execution context more or "
"less like different threads. [`Send` and `Sync`](../../concurrency/send-sync."
"md) will control what we can share between them, just like with threads. For "
"example, if we want to share some value between exception handlers and the "
"rest of the program, and it's `Send` but not `Sync`, then we'll need to wrap "
"it in something like a `Mutex` and put it in a static."
msgstr ""
#: src/bare-metal/aps/other-projects.md:3
#, fuzzy
msgid "[oreboot](https://github.com/oreboot/oreboot)"
msgstr "[oreboot](https://github.com/oreboot/oreboot)"
#: src/bare-metal/aps/other-projects.md:4
#, fuzzy
msgid "\"coreboot without the C\""
msgstr "\"C가 없는 coreboot\""
#: src/bare-metal/aps/other-projects.md:5
#, fuzzy
msgid "Supports x86, aarch64 and RISC-V."
msgstr "x86, aarch64, RISC-V를 지원합니다."
#: src/bare-metal/aps/other-projects.md:6
#, fuzzy
msgid "Relies on LinuxBoot rather than having many drivers itself."
msgstr "자체적으로 여러 드라이버를 보유하는 대신 LinuxBoot에 의존합니다."
#: src/bare-metal/aps/other-projects.md:7
#, fuzzy
msgid ""
"[Rust RaspberryPi OS tutorial](https://github.com/rust-embedded/rust-"
"raspberrypi-OS-tutorials)"
msgstr ""
"[Rust RaspberryPi OS tutorial](https://github.com/rust-embedded/rust-"
"raspberrypi-OS-tutorials)"
#: src/bare-metal/aps/other-projects.md:8
#, fuzzy
msgid ""
"Initialisation, UART driver, simple bootloader, JTAG, exception levels, "
"exception handling, page tables"
msgstr ""
"초기화, UART 드라이버, 간단한 부트로더, JTAG, 예외 수준, 예외 처리, 페이지 테"
"이블"
#: src/bare-metal/aps/other-projects.md:10
#, fuzzy
msgid ""
"Some dodginess around cache maintenance and initialisation in Rust, not "
"necessarily a good example to copy for production code."
msgstr "잘 작성되지 않은 것도 있으므로 주의하세요."
#: src/bare-metal/aps/other-projects.md:12
#, fuzzy
msgid "[`cargo-call-stack`](https://crates.io/crates/cargo-call-stack)"
msgstr "[`cargo-call-stack`](https://crates.io/crates/cargo-call-stack)"
#: src/bare-metal/aps/other-projects.md:13
#, fuzzy
msgid "Static analysis to determine maximum stack usage."
msgstr "최대 스택 사용량을 결정하는 정적 분석"
#: src/bare-metal/aps/other-projects.md:17
msgid ""
"The RaspberryPi OS tutorial runs Rust code before the MMU and caches are "
"enabled. This will read and write memory (e.g. the stack). However:"
msgstr ""
#: src/bare-metal/aps/other-projects.md:19
msgid ""
"Without the MMU and cache, unaligned accesses will fault. It builds with "
"`aarch64-unknown-none` which sets `+strict-align` to prevent the compiler "
"generating unaligned accesses so it should be alright, but this is not "
"necessarily the case in general."
msgstr ""
#: src/bare-metal/aps/other-projects.md:22
msgid ""
"If it were running in a VM, this can lead to cache coherency issues. The "
"problem is that the VM is accessing memory directly with the cache disabled, "
"while the host has cachable aliases to the same memory. Even if the host "
"doesn't explicitly access the memory, speculative accesses can lead to cache "
"fills, and then changes from one or the other will get lost. Again this is "
"alright in this particular case (running directly on the hardware with no "
"hypervisor), but isn't a good pattern in general."
msgstr ""
#: src/bare-metal/useful-crates.md:3
msgid ""
"We'll go over a few crates which solve some common problems in bare-metal "
"programming."
msgstr ""
"bare-metal 프로그래밍의 몇 가지 일반적인 문제를 해결하는 크레이트를 살펴봅니"
"다."
#: src/bare-metal/useful-crates/zerocopy.md:1
msgid "`zerocopy`"
msgstr "`zerocopy`"
#: src/bare-metal/useful-crates/zerocopy.md:3
msgid ""
"The [`zerocopy`](https://docs.rs/zerocopy/) crate (from Fuchsia) provides "
"traits and macros for safely converting between byte sequences and other "
"types."
msgstr ""
"Fuchsia팀이 만든 [`zerocopy`](https://docs.rs/zerocopy/) 크레이트는 바이트 시"
"퀀스를 다른 타입으로 안전하게 변환하기 위한 트레잇 및 매크로를 제공합니다."
#: src/bare-metal/useful-crates/zerocopy.md:6
msgid ""
"```rust,editable,compile_fail\n"
"use zerocopy::AsBytes;\n"
"\n"
"#[repr(u32)]\n"
"#[derive(AsBytes, Debug, Default)]\n"
"enum RequestType {\n"
" #[default]\n"
" In = 0,\n"
" Out = 1,\n"
" Flush = 4,\n"
"}\n"
"\n"
"#[repr(C)]\n"
"#[derive(AsBytes, Debug, Default)]\n"
"struct VirtioBlockRequest {\n"
" request_type: RequestType,\n"
" reserved: u32,\n"
" sector: u64,\n"
"}\n"
"\n"
"fn main() {\n"
" let request = VirtioBlockRequest {\n"
" request_type: RequestType::Flush,\n"
" sector: 42,\n"
" ..Default::default()\n"
" };\n"
"\n"
" assert_eq!(\n"
" request.as_bytes(),\n"
" &[4, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0]\n"
" );\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use zerocopy::AsBytes;\n"
"\n"
"#[repr(u32)]\n"
"#[derive(AsBytes, Debug, Default)]\n"
"enum RequestType {\n"
" #[default]\n"
" In = 0,\n"
" Out = 1,\n"
" Flush = 4,\n"
"}\n"
"\n"
"#[repr(C)]\n"
"#[derive(AsBytes, Debug, Default)]\n"
"struct VirtioBlockRequest {\n"
" request_type: RequestType,\n"
" reserved: u32,\n"
" sector: u64,\n"
"}\n"
"\n"
"fn main() {\n"
" let request = VirtioBlockRequest {\n"
" request_type: RequestType::Flush,\n"
" sector: 42,\n"
" ..Default::default()\n"
" };\n"
"\n"
" assert_eq!(\n"
" request.as_bytes(),\n"
" &[4, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0]\n"
" );\n"
"}\n"
"```"
#: src/bare-metal/useful-crates/zerocopy.md:40
msgid ""
"This is not suitable for MMIO (as it doesn't use volatile reads and writes), "
"but can be useful for working with structures shared with hardware e.g. by "
"DMA, or sent over some external interface."
msgstr ""
"이 크레이트는 휘발성(volatile) 읽기 및 쓰기를 사용하지 않으므로 MMIO에 적합하"
"지 않지만, 하드웨어와 공유되거나(예: DMA에서) 외장 인터페이스를 통해 전송되"
"는 구조체를 다루는 데에는 유용할 수 있습니다."
#: src/bare-metal/useful-crates/zerocopy.md:45
msgid ""
"`FromBytes` can be implemented for types for which any byte pattern is "
"valid, and so can safely be converted from an untrusted sequence of bytes."
msgstr ""
"어떤 타입이 가능한 모든 바이트 패턴들에 대해 올바른 값을 가질 때에만 , 그 타"
"입이 `FromBytes`를 구현할 수 있습니다. 그렇게 해서 신뢰할 수 없는 바이트 시퀀"
"스를 안전하게 해당 타입으로 변환할 수 있습니다."
#: src/bare-metal/useful-crates/zerocopy.md:47
msgid ""
"Attempting to derive `FromBytes` for these types would fail, because "
"`RequestType` doesn't use all possible u32 values as discriminants, so not "
"all byte patterns are valid."
msgstr ""
"위 코드에서 정의한 타입에 대해 `FromBytes`를 구현하려고 하면 에러가 발생합니"
"다. `RequestType`은 가능한 모든 u32 값을 식별자로 받아들이지 않기 때문입니"
"다. 즉 모든 바이트 패턴이 유효한 `RequestType`값은 아닙니다."
#: src/bare-metal/useful-crates/zerocopy.md:49
msgid ""
"`zerocopy::byteorder` has types for byte-order aware numeric primitives."
msgstr ""
"`zerocopy::byteorder`에는 바이트 오더에 따른 서로 다른 표현 방식을 지원하는 "
"숫자 타입을 제공합니다."
#: src/bare-metal/useful-crates/zerocopy.md:50
msgid ""
"Run the example with `cargo run` under `src/bare-metal/useful-crates/"
"zerocopy-example/`. (It won't run in the Playground because of the crate "
"dependency.)"
msgstr ""
"`src/bare-metal/useful-crates/zerocopy-example/`에서 `cargo run`을 사용하여 "
"예시를 실행합니다(종속성 문제로 인해 플레이그라운드에서는 실행되지 않습니다)."
#: src/bare-metal/useful-crates/aarch64-paging.md:1
msgid "`aarch64-paging`"
msgstr "`aarch64-paging`"
#: src/bare-metal/useful-crates/aarch64-paging.md:3
msgid ""
"The [`aarch64-paging`](https://crates.io/crates/aarch64-paging) crate lets "
"you create page tables according to the AArch64 Virtual Memory System "
"Architecture."
msgstr ""
"[`aarch64-paging`](https://crates.io/crates/aarch64-paging) 크레이트를 사용하"
"면 AArch64 가상 메모리 시스템 아키텍처에 따라 페이지 테이블을 만들 수 있습니"
"다."
#: src/bare-metal/useful-crates/aarch64-paging.md:6
msgid ""
"```rust,editable,compile_fail\n"
"use aarch64_paging::{\n"
" idmap::IdMap,\n"
" paging::{Attributes, MemoryRegion},\n"
"};\n"
"\n"
"const ASID: usize = 1;\n"
"const ROOT_LEVEL: usize = 1;\n"
"\n"
"// Create a new page table with identity mapping.\n"
"let mut idmap = IdMap::new(ASID, ROOT_LEVEL);\n"
"// Map a 2 MiB region of memory as read-only.\n"
"idmap.map_range(\n"
" &MemoryRegion::new(0x80200000, 0x80400000),\n"
" Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,\n"
").unwrap();\n"
"// Set `TTBR0_EL1` to activate the page table.\n"
"idmap.activate();\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use aarch64_paging::{\n"
" idmap::IdMap,\n"
" paging::{Attributes, MemoryRegion},\n"
"};\n"
"\n"
"const ASID: usize = 1;\n"
"const ROOT_LEVEL: usize = 1;\n"
"\n"
"// 상동(identity) 매핑으로 새로운 페이지 테이블을 만듭니다.\n"
"let mut idmap = IdMap::new(ASID, ROOT_LEVEL);\n"
"// 2MiB 메모리 영역을 읽기 전용으로 매핑합니다.\n"
"idmap.map_range(\n"
" &MemoryRegion::new(0x80200000, 0x80400000),\n"
" Attributes::NORMAL | Attributes::NON_GLOBAL | Attributes::READ_ONLY,\n"
").unwrap();\n"
"// 페이지 테이블을 활성화하도록 `TTBR0_EL1`을 설정합니다.\n"
"idmap.activate();\n"
"```"
#: src/bare-metal/useful-crates/aarch64-paging.md:28
msgid ""
"For now it only supports EL1, but support for other exception levels should "
"be straightforward to add."
msgstr ""
"현재는 EL1만 지원하지만 다른 익셉션 레벨(Exception Level: EL)도 어렵지 않게 "
"추가할 수 있습니다."
#: src/bare-metal/useful-crates/aarch64-paging.md:30
msgid ""
"This is used in Android for the [Protected VM Firmware](https://cs.android."
"com/android/platform/superproject/+/master:packages/modules/Virtualization/"
"pvmfw/)."
msgstr ""
"Android에서 [보호된 VM 펌웨어](https://cs.android.com/android/platform/"
"superproject/+/master:packages/modules/Virtualization/pvmfw/)에 사용됩니다."
#: src/bare-metal/useful-crates/aarch64-paging.md:31
msgid ""
"There's no easy way to run this example, as it needs to run on real hardware "
"or under QEMU."
msgstr ""
"이 예시를 간단하게 실행하는 방법은 없습니다. 실제 하드웨어 또는 QEMU에서 실행"
"해야 하기 때문입니다."
#: src/bare-metal/useful-crates/buddy_system_allocator.md:1
msgid "`buddy_system_allocator`"
msgstr "`buddy_system_allocator`"
#: src/bare-metal/useful-crates/buddy_system_allocator.md:3
msgid ""
"[`buddy_system_allocator`](https://crates.io/crates/buddy_system_allocator) "
"is a third-party crate implementing a basic buddy system allocator. It can "
"be used both for [`LockedHeap`](https://docs.rs/buddy_system_allocator/0.9.0/"
"buddy_system_allocator/struct.LockedHeap.html) implementing [`GlobalAlloc`]"
"(https://doc.rust-lang.org/core/alloc/trait.GlobalAlloc.html) so you can use "
"the standard `alloc` crate (as we saw [before](../alloc.md)), or for "
"allocating other address space. For example, we might want to allocate MMIO "
"space for PCI BARs:"
msgstr ""
"[`buddy_system_allocator`](https://crates.io/crates/buddy_system_allocator)"
"는 버디 시스템 할당자를 구현하는 서드 파티 크레이트입니다. 이 크레이트의 "
"[`LockedHeap`](https://docs.rs/buddy_system_allocator/0.9.0/"
"buddy_system_allocator/struct.LockedHeap.html)은 [`GlobalAlloc`](https://doc."
"rust-lang.org/core/alloc/trait.GlobalAlloc.html)를 구현합니다. 따라서 여러분"
"은 버디 시스템 할당자를 'alloc' 크레이트를 통해서 사용할 수 있습니다([이전]"
"(../alloc.md)에 확인함). 또는 다른 주소 공간을 할당하는 데 사용할 수 있습니"
"다. 예를 들어 PCI BAR에 MMIO 공간을 할당할 수 있습니다."
#: src/bare-metal/useful-crates/buddy_system_allocator.md:8
msgid ""
"```rust,editable,compile_fail\n"
"use buddy_system_allocator::FrameAllocator;\n"
"use core::alloc::Layout;\n"
"\n"
"fn main() {\n"
" let mut allocator = FrameAllocator::<32>::new();\n"
" allocator.add_frame(0x200_0000, 0x400_0000);\n"
"\n"
" let layout = Layout::from_size_align(0x100, 0x100).unwrap();\n"
" let bar = allocator\n"
" .alloc_aligned(layout)\n"
" .expect(\"Failed to allocate 0x100 byte MMIO region\");\n"
" println!(\"Allocated 0x100 byte MMIO region at {:#x}\", bar);\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use buddy_system_allocator::FrameAllocator;\n"
"use core::alloc::Layout;\n"
"\n"
"fn main() {\n"
" let mut allocator = FrameAllocator::<32>::new();\n"
" allocator.add_frame(0x200_0000, 0x400_0000);\n"
"\n"
" let layout = Layout::from_size_align(0x100, 0x100).unwrap();\n"
" let bar = allocator\n"
" .alloc_aligned(layout)\n"
" .expect(\"Failed to allocate 0x100 byte MMIO region\");\n"
" println!(\"Allocated 0x100 byte MMIO region at {:#x}\", bar);\n"
"}\n"
"```"
#: src/bare-metal/useful-crates/buddy_system_allocator.md:26
msgid "PCI BARs always have alignment equal to their size."
msgstr "PCI BAR는 BAR영역의 크기에 맞추어 정렬됩니다."
#: src/bare-metal/useful-crates/buddy_system_allocator.md:27
msgid ""
"Run the example with `cargo run` under `src/bare-metal/useful-crates/"
"allocator-example/`. (It won't run in the Playground because of the crate "
"dependency.)"
msgstr ""
"`src/bare-metal/useful-crates/allocator-example/`에서 `cargo run`을 사용하여 "
"예시를 실행합니다(종속성 문제로 인해 플레이그라운드에서는 실행되지 않습니다)."
#: src/bare-metal/useful-crates/tinyvec.md:1
msgid "`tinyvec`"
msgstr "`tinyvec`"
#: src/bare-metal/useful-crates/tinyvec.md:3
msgid ""
"Sometimes you want something which can be resized like a `Vec`, but without "
"heap allocation. [`tinyvec`](https://crates.io/crates/tinyvec) provides "
"this: a vector backed by an array or slice, which could be statically "
"allocated or on the stack, which keeps track of how many elements are used "
"and panics if you try to use more than are allocated."
msgstr ""
"힙에 메모리 할당하지 않고 크기 조절이 가능한 컨테이너(예: `Vec` 같은)가 필요"
"할 때가 있습니다. [`tinyvec`](https://crates.io/crates/tinyvec)을 사용하면 됩"
"니다. `tinyvec`에서 벡터는 배열 또는 슬라이스로부터 생성이 되며, 이들은 정적"
"으로 할당되었거나 스택에 할당되어 있을 수 있습니다.`tinyvec`은 현재 벡터 안"
"에 얼마나 많은 엘리먼트들이 존재하는 지를 추적하고 있으며, 할당된 양보다 더 "
"많이 사용하려고 하면 패닉을 발생시킵니다."
#: src/bare-metal/useful-crates/tinyvec.md:8
msgid ""
"```rust,editable,compile_fail\n"
"use tinyvec::{array_vec, ArrayVec};\n"
"\n"
"fn main() {\n"
" let mut numbers: ArrayVec<[u32; 5]> = array_vec!(42, 66);\n"
" println!(\"{numbers:?}\");\n"
" numbers.push(7);\n"
" println!(\"{numbers:?}\");\n"
" numbers.remove(1);\n"
" println!(\"{numbers:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use tinyvec::{array_vec, ArrayVec};\n"
"\n"
"fn main() {\n"
" let mut numbers: ArrayVec<[u32; 5]> = array_vec!(42, 66);\n"
" println!(\"{numbers:?}\");\n"
" numbers.push(7);\n"
" println!(\"{numbers:?}\");\n"
" numbers.remove(1);\n"
" println!(\"{numbers:?}\");\n"
"}\n"
"```"
#: src/bare-metal/useful-crates/tinyvec.md:23
msgid ""
"`tinyvec` requires that the element type implement `Default` for "
"initialisation."
msgstr ""
"`tinyvec`를 사용하려면 엘리먼트의 타입이 `Default`를 통해 초기화 될 수 있어"
"야 합니다."
#: src/bare-metal/useful-crates/tinyvec.md:24
msgid ""
"The Rust Playground includes `tinyvec`, so this example will run fine inline."
msgstr ""
"Rust 플레이그라운드에는 `tinyvec`가 포함되어 있으므로 이 예시는 인라인으로 실"
"행됩니다."
#: src/bare-metal/useful-crates/spin.md:1
#, fuzzy
msgid "`spin`"
msgstr "회전"
#: src/bare-metal/useful-crates/spin.md:3
msgid ""
"`std::sync::Mutex` and the other synchronisation primitives from `std::sync` "
"are not available in `core` or `alloc`. How can we manage synchronisation or "
"interior mutability, such as for sharing state between different CPUs?"
msgstr ""
"`std::sync::Mutex` 및 `std::sync`의 기타 동기화 프리미티브는 `core` 또는 "
"`alloc`에서 사용할 수 없습니다. 그러면 어떻게 동기화 또는 interior mutability"
"와 같은 기능이 필요할 경우 어떻게 해야 할까요? "
#: src/bare-metal/useful-crates/spin.md:7
msgid ""
"The [`spin`](https://crates.io/crates/spin) crate provides spinlock-based "
"equivalents of many of these primitives."
msgstr ""
"[`spin`](https://crates.io/crates/spin) 크레이트는 이러한 동기화 프리미티브들"
"을 스핀록으로 구현하고 있습니다."
#: src/bare-metal/useful-crates/spin.md:9
msgid ""
"```rust,editable,compile_fail\n"
"use spin::mutex::SpinMutex;\n"
"\n"
"static counter: SpinMutex<u32> = SpinMutex::new(0);\n"
"\n"
"fn main() {\n"
" println!(\"count: {}\", counter.lock());\n"
" *counter.lock() += 2;\n"
" println!(\"count: {}\", counter.lock());\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use spin::mutex::SpinMutex;\n"
"\n"
"static counter: SpinMutex<u32> = SpinMutex::new(0);\n"
"\n"
"fn main() {\n"
" println!(\"count: {}\", counter.lock());\n"
" *counter.lock() += 2;\n"
" println!(\"count: {}\", counter.lock());\n"
"}\n"
"```"
#: src/bare-metal/useful-crates/spin.md:23
msgid "Be careful to avoid deadlock if you take locks in interrupt handlers."
msgstr ""
"인터럽트 핸들러에서 락을 걸 경우, 교착 상태가 발생하지 않도록 주의하세요."
#: src/bare-metal/useful-crates/spin.md:24
msgid ""
"`spin` also has a ticket lock mutex implementation; equivalents of `RwLock`, "
"`Barrier` and `Once` from `std::sync`; and `Lazy` for lazy initialisation."
msgstr ""
"`spin`에는 티켓 잠금 뮤텍스 구현도 있습니다. `std::sync`의 `RwLock`, "
"`Barrier`, `Once` 에 해당하는 것들이 제공되며, 지연된 초기화를 위한 `Lazy`"
"에 해당하는 것도 제공됩니다."
#: src/bare-metal/useful-crates/spin.md:26
msgid ""
"The [`once_cell`](https://crates.io/crates/once_cell) crate also has some "
"useful types for late initialisation with a slightly different approach to "
"`spin::once::Once`."
msgstr ""
"[`once_cell`](https://crates.io/crates/once_cell) 크레이트에는 지연된 초기화"
"를 위한 몇 가지 유용한 타입이 있는데 `spin::once::Once`와는 약간 다른 접근 방"
"식을 사용합니다."
#: src/bare-metal/useful-crates/spin.md:28
msgid ""
"The Rust Playground includes `spin`, so this example will run fine inline."
msgstr ""
"Rust 플레이그라운드에는 `spin`이 포함되어 있으므로 이 예시는 인라인으로 실행"
"됩니다."
#: src/bare-metal/android.md:3
msgid ""
"To build a bare-metal Rust binary in AOSP, you need to use a "
"`rust_ffi_static` Soong rule to build your Rust code, then a `cc_binary` "
"with a linker script to produce the binary itself, and then a `raw_binary` "
"to convert the ELF to a raw binary ready to be run."
msgstr ""
"AOSP에서 bare-metal Rust 바이너리를 빌드하려면 `rust_ffi_static` 을 사용하여 "
"Rust 코드를 빌드하고, 링커 스크립트가 포함된 `cc_binary`를 사용하여 ELF 바이"
"너리를 생성하고, `raw_binary`를 사용해 ELF를 곧바로 수행될 수 있는 원시(raw) "
"바이너리로 변환합니다."
#: src/bare-metal/android.md:7
msgid ""
"```soong\n"
"rust_ffi_static {\n"
" name: \"libvmbase_example\",\n"
" defaults: [\"vmbase_ffi_defaults\"],\n"
" crate_name: \"vmbase_example\",\n"
" srcs: [\"src/main.rs\"],\n"
" rustlibs: [\n"
" \"libvmbase\",\n"
" ],\n"
"}\n"
"\n"
"cc_binary {\n"
" name: \"vmbase_example\",\n"
" defaults: [\"vmbase_elf_defaults\"],\n"
" srcs: [\n"
" \"idmap.S\",\n"
" ],\n"
" static_libs: [\n"
" \"libvmbase_example\",\n"
" ],\n"
" linker_scripts: [\n"
" \"image.ld\",\n"
" \":vmbase_sections\",\n"
" ],\n"
"}\n"
"\n"
"raw_binary {\n"
" name: \"vmbase_example_bin\",\n"
" stem: \"vmbase_example.bin\",\n"
" src: \":vmbase_example\",\n"
" enabled: false,\n"
" target: {\n"
" android_arm64: {\n"
" enabled: true,\n"
" },\n"
" },\n"
"}\n"
"```"
msgstr ""
"```soong\n"
"rust_ffi_static {\n"
" name: \"libvmbase_example\",\n"
" defaults: [\"vmbase_ffi_defaults\"],\n"
" crate_name: \"vmbase_example\",\n"
" srcs: [\"src/main.rs\"],\n"
" rustlibs: [\n"
" \"libvmbase\",\n"
" ],\n"
"}\n"
"\n"
"cc_binary {\n"
" name: \"vmbase_example\",\n"
" defaults: [\"vmbase_elf_defaults\"],\n"
" srcs: [\n"
" \"idmap.S\",\n"
" ],\n"
" static_libs: [\n"
" \"libvmbase_example\",\n"
" ],\n"
" linker_scripts: [\n"
" \"image.ld\",\n"
" \":vmbase_sections\",\n"
" ],\n"
"}\n"
"\n"
"raw_binary {\n"
" name: \"vmbase_example_bin\",\n"
" stem: \"vmbase_example.bin\",\n"
" src: \":vmbase_example\",\n"
" enabled: false,\n"
" target: {\n"
" android_arm64: {\n"
" enabled: true,\n"
" },\n"
" },\n"
"}\n"
"```"
#: src/bare-metal/android/vmbase.md:3
msgid ""
"For VMs running under crosvm on aarch64, the [vmbase](https://android."
"googlesource.com/platform/packages/modules/Virtualization/+/refs/heads/"
"master/vmbase/) library provides a linker script and useful defaults for the "
"build rules, along with an entry point, UART console logging and more."
msgstr ""
"[vmbase](https://android.googlesource.com/platform/packages/modules/"
"Virtualization/+/refs/heads/master/vmbase/) 라이브러리는, aarch64의 crosvm에"
"서 실행되는 VM을 타겟하여, 진입점, UART 콘솔 로깅, 링커 스크립트, 빌드 룰 등"
"에 대한 기본 구현들을 제공합니다."
#: src/bare-metal/android/vmbase.md:6
msgid ""
"```rust,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"use vmbase::{main, println};\n"
"\n"
"main!(main);\n"
"\n"
"pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {\n"
" println!(\"Hello world\");\n"
"}\n"
"```"
msgstr ""
"```rust,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"use vmbase::{main, println};\n"
"\n"
"main!(main);\n"
"\n"
"pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {\n"
" println!(\"Hello world\");\n"
"}\n"
"```"
#: src/bare-metal/android/vmbase.md:21
msgid ""
"The `main!` macro marks your main function, to be called from the `vmbase` "
"entry point."
msgstr "`main!` 매크로는 `vmbase` 진입점에서 호출될 main 함수를 표시합니다."
#: src/bare-metal/android/vmbase.md:22
msgid ""
"The `vmbase` entry point handles console initialisation, and issues a "
"PSCI_SYSTEM_OFF to shutdown the VM if your main function returns."
msgstr ""
"`vmbase`가 제공하는 진입점은 콘솔을 초기화 하며, main 함수가 리턴하면 "
"PSCI_SYSTEM_OFF 메시지를 PSCI를 통해 보내어서 VM을 종료시킵니다."
#: src/exercises/bare-metal/afternoon.md:3
msgid "We will write a driver for the PL031 real-time clock device."
msgstr ""
#: src/exercises/bare-metal/rtc.md:1
#: src/exercises/bare-metal/solutions-afternoon.md:3
#, fuzzy
msgid "RTC driver"
msgstr "RTC 드라이버"
#: src/exercises/bare-metal/rtc.md:3
#, fuzzy
msgid ""
"The QEMU aarch64 virt machine has a [PL031](https://developer.arm.com/"
"documentation/ddi0224/c) real-time clock at 0x9010000. For this exercise, "
"you should write a driver for it."
msgstr ""
"QEMU의 'virt' 보드에는 [PL011](https://developer.arm.com/documentation/"
"ddi0224/c) UART가 있으므로 이를 위한 드라이버를 작성해 보겠습니다."
#: src/exercises/bare-metal/rtc.md:6
msgid ""
"Use it to print the current time to the serial console. You can use the "
"[`chrono`](https://crates.io/crates/chrono) crate for date/time formatting."
msgstr ""
#: src/exercises/bare-metal/rtc.md:8
msgid ""
"Use the match register and raw interrupt status to busy-wait until a given "
"time, e.g. 3 seconds in the future. (Call [`core::hint::spin_loop`](https://"
"doc.rust-lang.org/core/hint/fn.spin_loop.html) inside the loop.)"
msgstr ""
#: src/exercises/bare-metal/rtc.md:10
msgid ""
"_Extension if you have time:_ Enable and handle the interrupt generated by "
"the RTC match. You can use the driver provided in the [`arm-gic`](https://"
"docs.rs/arm-gic/) crate to configure the Arm Generic Interrupt Controller."
msgstr ""
#: src/exercises/bare-metal/rtc.md:12
msgid "Use the RTC interrupt, which is wired to the GIC as `IntId::spi(2)`."
msgstr ""
#: src/exercises/bare-metal/rtc.md:13
msgid ""
"Once the interrupt is enabled, you can put the core to sleep via `arm_gic::"
"wfi()`, which will cause the core to sleep until it receives an interrupt."
msgstr ""
#: src/exercises/bare-metal/rtc.md:16
msgid ""
"Download the [exercise template](../../comprehensive-rust-exercises.zip) and "
"look in the `rtc` directory for the following files."
msgstr ""
#: src/exercises/bare-metal/rtc.md:23
msgid ""
"```rust,compile_fail\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"mod exceptions;\n"
"mod logger;\n"
"mod pl011;\n"
"\n"
"use crate::pl011::Uart;\n"
"use arm_gic::gicv3::GicV3;\n"
"use core::panic::PanicInfo;\n"
"use log::{error, info, trace, LevelFilter};\n"
"use smccc::psci::system_off;\n"
"use smccc::Hvc;\n"
"\n"
"/// Base addresses of the GICv3.\n"
"const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;\n"
"const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;\n"
"\n"
"/// Base address of the primary PL011 UART.\n"
"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n"
" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 "
"device,\n"
" // and nothing else accesses that address range.\n"
" let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n"
" logger::init(uart, LevelFilter::Trace).unwrap();\n"
"\n"
" info!(\"main({:#x}, {:#x}, {:#x}, {:#x})\", x0, x1, x2, x3);\n"
"\n"
" // Safe because `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the "
"base\n"
" // addresses of a GICv3 distributor and redistributor respectively, and\n"
" // nothing else accesses those address ranges.\n"
" let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, "
"GICR_BASE_ADDRESS) };\n"
" gic.setup();\n"
"\n"
" // TODO: Create instance of RTC driver and print current time.\n"
"\n"
" // TODO: Wait for 3 seconds.\n"
"\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[panic_handler]\n"
"fn panic(info: &PanicInfo) -> ! {\n"
" error!(\"{info}\");\n"
" system_off::<Hvc>().unwrap();\n"
" loop {}\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:75
msgid ""
"`src/exceptions.rs` (you should only need to change this for the 3rd part of "
"the exercise):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:79
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"use arm_gic::gicv3::GicV3;\n"
"use log::{error, info, trace};\n"
"use smccc::psci::system_off;\n"
"use smccc::Hvc;\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn sync_exception_current(_elr: u64, _spsr: u64) {\n"
" error!(\"sync_exception_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn irq_current(_elr: u64, _spsr: u64) {\n"
" trace!(\"irq_current\");\n"
" let intid = GicV3::get_and_acknowledge_interrupt().expect(\"No pending "
"interrupt\");\n"
" info!(\"IRQ {intid:?}\");\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn fiq_current(_elr: u64, _spsr: u64) {\n"
" error!(\"fiq_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn serr_current(_elr: u64, _spsr: u64) {\n"
" error!(\"serr_current\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn sync_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"sync_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn irq_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"irq_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn fiq_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"fiq_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[no_mangle]\n"
"extern \"C\" fn serr_lower(_elr: u64, _spsr: u64) {\n"
" error!(\"serr_lower\");\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:149
msgid "`src/logger.rs` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:153
#, fuzzy
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: main\n"
"use crate::pl011::Uart;\n"
"use core::fmt::Write;\n"
"use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};\n"
"use spin::mutex::SpinMutex;\n"
"\n"
"static LOGGER: Logger = Logger {\n"
" uart: SpinMutex::new(None),\n"
"};\n"
"\n"
"struct Logger {\n"
" uart: SpinMutex<Option<Uart>>,\n"
"}\n"
"\n"
"impl Log for Logger {\n"
" fn enabled(&self, _metadata: &Metadata) -> bool {\n"
" true\n"
" }\n"
"\n"
" fn log(&self, record: &Record) {\n"
" writeln!(\n"
" self.uart.lock().as_mut().unwrap(),\n"
" \"[{}] {}\",\n"
" record.level(),\n"
" record.args()\n"
" )\n"
" .unwrap();\n"
" }\n"
"\n"
" fn flush(&self) {}\n"
"}\n"
"\n"
"/// Initialises UART logger.\n"
"pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), "
"SetLoggerError> {\n"
" LOGGER.uart.lock().replace(uart);\n"
"\n"
" log::set_logger(&LOGGER)?;\n"
" log::set_max_level(max_level);\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use crate::pl011::Uart;\n"
"use core::fmt::Write;\n"
"use log::{LevelFilter, Log, Metadata, Record, SetLoggerError};\n"
"use spin::mutex::SpinMutex;\n"
"\n"
"static LOGGER: Logger = Logger {\n"
" uart: SpinMutex::new(None),\n"
"};\n"
"\n"
"struct Logger {\n"
" uart: SpinMutex<Option<Uart>>,\n"
"}\n"
"\n"
"impl Log for Logger {\n"
" fn enabled(&self, _metadata: &Metadata) -> bool {\n"
" true\n"
" }\n"
"\n"
" fn log(&self, record: &Record) {\n"
" writeln!(\n"
" self.uart.lock().as_mut().unwrap(),\n"
" \"[{}] {}\",\n"
" record.level(),\n"
" record.args()\n"
" )\n"
" .unwrap();\n"
" }\n"
"\n"
" fn flush(&self) {}\n"
"}\n"
"\n"
"/// UART 로거를 초기화합니다.\n"
"pub fn init(uart: Uart, max_level: LevelFilter) -> Result<(), "
"SetLoggerError> {\n"
" LOGGER.uart.lock().replace(uart);\n"
"\n"
" log::set_logger(&LOGGER)?;\n"
" log::set_max_level(max_level);\n"
" Ok(())\n"
"}\n"
"```"
#: src/exercises/bare-metal/rtc.md:210
msgid "`src/pl011.rs` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:214
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"#![allow(unused)]\n"
"\n"
"use core::fmt::{self, Write};\n"
"use core::ptr::{addr_of, addr_of_mut};\n"
"\n"
"// ANCHOR: Flags\n"
"use bitflags::bitflags;\n"
"\n"
"bitflags! {\n"
" /// Flags from the UART flag register.\n"
" #[repr(transparent)]\n"
" #[derive(Copy, Clone, Debug, Eq, PartialEq)]\n"
" struct Flags: u16 {\n"
" /// Clear to send.\n"
" const CTS = 1 << 0;\n"
" /// Data set ready.\n"
" const DSR = 1 << 1;\n"
" /// Data carrier detect.\n"
" const DCD = 1 << 2;\n"
" /// UART busy transmitting data.\n"
" const BUSY = 1 << 3;\n"
" /// Receive FIFO is empty.\n"
" const RXFE = 1 << 4;\n"
" /// Transmit FIFO is full.\n"
" const TXFF = 1 << 5;\n"
" /// Receive FIFO is full.\n"
" const RXFF = 1 << 6;\n"
" /// Transmit FIFO is empty.\n"
" const TXFE = 1 << 7;\n"
" /// Ring indicator.\n"
" const RI = 1 << 8;\n"
" }\n"
"}\n"
"// ANCHOR_END: Flags\n"
"\n"
"bitflags! {\n"
" /// Flags from the UART Receive Status Register / Error Clear Register.\n"
" #[repr(transparent)]\n"
" #[derive(Copy, Clone, Debug, Eq, PartialEq)]\n"
" struct ReceiveStatus: u16 {\n"
" /// Framing error.\n"
" const FE = 1 << 0;\n"
" /// Parity error.\n"
" const PE = 1 << 1;\n"
" /// Break error.\n"
" const BE = 1 << 2;\n"
" /// Overrun error.\n"
" const OE = 1 << 3;\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Registers\n"
"#[repr(C, align(4))]\n"
"struct Registers {\n"
" dr: u16,\n"
" _reserved0: [u8; 2],\n"
" rsr: ReceiveStatus,\n"
" _reserved1: [u8; 19],\n"
" fr: Flags,\n"
" _reserved2: [u8; 6],\n"
" ilpr: u8,\n"
" _reserved3: [u8; 3],\n"
" ibrd: u16,\n"
" _reserved4: [u8; 2],\n"
" fbrd: u8,\n"
" _reserved5: [u8; 3],\n"
" lcr_h: u8,\n"
" _reserved6: [u8; 3],\n"
" cr: u16,\n"
" _reserved7: [u8; 3],\n"
" ifls: u8,\n"
" _reserved8: [u8; 3],\n"
" imsc: u16,\n"
" _reserved9: [u8; 2],\n"
" ris: u16,\n"
" _reserved10: [u8; 2],\n"
" mis: u16,\n"
" _reserved11: [u8; 2],\n"
" icr: u16,\n"
" _reserved12: [u8; 2],\n"
" dmacr: u8,\n"
" _reserved13: [u8; 3],\n"
"}\n"
"// ANCHOR_END: Registers\n"
"\n"
"// ANCHOR: Uart\n"
"/// Driver for a PL011 UART.\n"
"#[derive(Debug)]\n"
"pub struct Uart {\n"
" registers: *mut Registers,\n"
"}\n"
"\n"
"impl Uart {\n"
" /// Constructs a new instance of the UART driver for a PL011 device at "
"the\n"
" /// given base address.\n"
" ///\n"
" /// # Safety\n"
" ///\n"
" /// The given base address must point to the MMIO control registers of "
"a\n"
" /// PL011 device, which must be mapped into the address space of the "
"process\n"
" /// as device memory and not have any other aliases.\n"
" pub unsafe fn new(base_address: *mut u32) -> Self {\n"
" Self {\n"
" registers: base_address as *mut Registers,\n"
" }\n"
" }\n"
"\n"
" /// Writes a single byte to the UART.\n"
" pub fn write_byte(&self, byte: u8) {\n"
" // Wait until there is room in the TX buffer.\n"
" while self.read_flag_register().contains(Flags::TXFF) {}\n"
"\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe {\n"
" // Write to the TX buffer.\n"
" addr_of_mut!((*self.registers).dr).write_volatile(byte.into());\n"
" }\n"
"\n"
" // Wait until the UART is no longer busy.\n"
" while self.read_flag_register().contains(Flags::BUSY) {}\n"
" }\n"
"\n"
" /// Reads and returns a pending byte, or `None` if nothing has been "
"received.\n"
" pub fn read_byte(&self) -> Option<u8> {\n"
" if self.read_flag_register().contains(Flags::RXFE) {\n"
" None\n"
" } else {\n"
" let data = unsafe { addr_of!((*self.registers).dr)."
"read_volatile() };\n"
" // TODO: Check for error conditions in bits 8-11.\n"
" Some(data as u8)\n"
" }\n"
" }\n"
"\n"
" fn read_flag_register(&self) -> Flags {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL011 device which is appropriately mapped.\n"
" unsafe { addr_of!((*self.registers).fr).read_volatile() }\n"
" }\n"
"}\n"
"// ANCHOR_END: Uart\n"
"\n"
"impl Write for Uart {\n"
" fn write_str(&mut self, s: &str) -> fmt::Result {\n"
" for c in s.as_bytes() {\n"
" self.write_byte(*c);\n"
" }\n"
" Ok(())\n"
" }\n"
"}\n"
"\n"
"// Safe because it just contains a pointer to device memory, which can be\n"
"// accessed from any context.\n"
"unsafe impl Send for Uart {}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:389
msgid ""
"```toml\n"
"[workspace]\n"
"\n"
"[package]\n"
"name = \"rtc\"\n"
"version = \"0.1.0\"\n"
"edition = \"2021\"\n"
"publish = false\n"
"\n"
"[dependencies]\n"
"arm-gic = \"0.1.0\"\n"
"bitflags = \"2.0.0\"\n"
"chrono = { version = \"0.4.24\", default-features = false }\n"
"log = \"0.4.17\"\n"
"smccc = \"0.1.1\"\n"
"spin = \"0.9.8\"\n"
"\n"
"[build-dependencies]\n"
"cc = \"1.0.73\"\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:410
msgid "`build.rs` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:414
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"use cc::Build;\n"
"use std::env;\n"
"\n"
"fn main() {\n"
" #[cfg(target_os = \"linux\")]\n"
" env::set_var(\"CROSS_COMPILE\", \"aarch64-linux-gnu\");\n"
" #[cfg(not(target_os = \"linux\"))]\n"
" env::set_var(\"CROSS_COMPILE\", \"aarch64-none-elf\");\n"
"\n"
" Build::new()\n"
" .file(\"entry.S\")\n"
" .file(\"exceptions.S\")\n"
" .file(\"idmap.S\")\n"
" .compile(\"empty\")\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:446
msgid "`entry.S` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:450
msgid ""
"```armasm\n"
"/*\n"
" * Copyright 2023 Google LLC\n"
" *\n"
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
" * you may not use this file except in compliance with the License.\n"
" * You may obtain a copy of the License at\n"
" *\n"
" * https://www.apache.org/licenses/LICENSE-2.0\n"
" *\n"
" * Unless required by applicable law or agreed to in writing, software\n"
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
" * See the License for the specific language governing permissions and\n"
" * limitations under the License.\n"
" */\n"
"\n"
".macro adr_l, reg:req, sym:req\n"
"\tadrp \\reg, \\sym\n"
"\tadd \\reg, \\reg, :lo12:\\sym\n"
".endm\n"
"\n"
".macro mov_i, reg:req, imm:req\n"
"\tmovz \\reg, :abs_g3:\\imm\n"
"\tmovk \\reg, :abs_g2_nc:\\imm\n"
"\tmovk \\reg, :abs_g1_nc:\\imm\n"
"\tmovk \\reg, :abs_g0_nc:\\imm\n"
".endm\n"
"\n"
".set .L_MAIR_DEV_nGnRE,\t0x04\n"
".set .L_MAIR_MEM_WBWA,\t0xff\n"
".set .Lmairval, .L_MAIR_DEV_nGnRE | (.L_MAIR_MEM_WBWA << 8)\n"
"\n"
"/* 4 KiB granule size for TTBR0_EL1. */\n"
".set .L_TCR_TG0_4KB, 0x0 << 14\n"
"/* 4 KiB granule size for TTBR1_EL1. */\n"
".set .L_TCR_TG1_4KB, 0x2 << 30\n"
"/* Disable translation table walk for TTBR1_EL1, generating a translation "
"fault instead. */\n"
".set .L_TCR_EPD1, 0x1 << 23\n"
"/* Translation table walks for TTBR0_EL1 are inner sharable. */\n"
".set .L_TCR_SH_INNER, 0x3 << 12\n"
"/*\n"
" * Translation table walks for TTBR0_EL1 are outer write-back read-allocate "
"write-allocate\n"
" * cacheable.\n"
" */\n"
".set .L_TCR_RGN_OWB, 0x1 << 10\n"
"/*\n"
" * Translation table walks for TTBR0_EL1 are inner write-back read-allocate "
"write-allocate\n"
" * cacheable.\n"
" */\n"
".set .L_TCR_RGN_IWB, 0x1 << 8\n"
"/* Size offset for TTBR0_EL1 is 2**39 bytes (512 GiB). */\n"
".set .L_TCR_T0SZ_512, 64 - 39\n"
".set .Ltcrval, .L_TCR_TG0_4KB | .L_TCR_TG1_4KB | .L_TCR_EPD1 | ."
"L_TCR_RGN_OWB\n"
".set .Ltcrval, .Ltcrval | .L_TCR_RGN_IWB | .L_TCR_SH_INNER | ."
"L_TCR_T0SZ_512\n"
"\n"
"/* Stage 1 instruction access cacheability is unaffected. */\n"
".set .L_SCTLR_ELx_I, 0x1 << 12\n"
"/* SP alignment fault if SP is not aligned to a 16 byte boundary. */\n"
".set .L_SCTLR_ELx_SA, 0x1 << 3\n"
"/* Stage 1 data access cacheability is unaffected. */\n"
".set .L_SCTLR_ELx_C, 0x1 << 2\n"
"/* EL0 and EL1 stage 1 MMU enabled. */\n"
".set .L_SCTLR_ELx_M, 0x1 << 0\n"
"/* Privileged Access Never is unchanged on taking an exception to EL1. */\n"
".set .L_SCTLR_EL1_SPAN, 0x1 << 23\n"
"/* SETEND instruction disabled at EL0 in aarch32 mode. */\n"
".set .L_SCTLR_EL1_SED, 0x1 << 8\n"
"/* Various IT instructions are disabled at EL0 in aarch32 mode. */\n"
".set .L_SCTLR_EL1_ITD, 0x1 << 7\n"
".set .L_SCTLR_EL1_RES1, (0x1 << 11) | (0x1 << 20) | (0x1 << 22) | (0x1 << "
"28) | (0x1 << 29)\n"
".set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | ."
"L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED\n"
".set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | ."
"L_SCTLR_EL1_RES1\n"
"\n"
"/**\n"
" * This is a generic entry point for an image. It carries out the operations "
"required to prepare the\n"
" * loaded image to be run. Specifically, it zeroes the bss section using "
"registers x25 and above,\n"
" * prepares the stack, enables floating point, and sets up the exception "
"vector. It preserves x0-x3\n"
" * for the Rust entry point, as these may contain boot parameters.\n"
" */\n"
".section .init.entry, \"ax\"\n"
".global entry\n"
"entry:\n"
"\t/* Load and apply the memory management configuration, ready to enable MMU "
"and caches. */\n"
"\tadrp x30, idmap\n"
"\tmsr ttbr0_el1, x30\n"
"\n"
"\tmov_i x30, .Lmairval\n"
"\tmsr mair_el1, x30\n"
"\n"
"\tmov_i x30, .Ltcrval\n"
"\t/* Copy the supported PA range into TCR_EL1.IPS. */\n"
"\tmrs x29, id_aa64mmfr0_el1\n"
"\tbfi x30, x29, #32, #4\n"
"\n"
"\tmsr tcr_el1, x30\n"
"\n"
"\tmov_i x30, .Lsctlrval\n"
"\n"
"\t/*\n"
"\t * Ensure everything before this point has completed, then invalidate any "
"potentially stale\n"
"\t * local TLB entries before they start being used.\n"
"\t */\n"
"\tisb\n"
"\ttlbi vmalle1\n"
"\tic iallu\n"
"\tdsb nsh\n"
"\tisb\n"
"\n"
"\t/*\n"
"\t * Configure sctlr_el1 to enable MMU and cache and don't proceed until "
"this has completed.\n"
"\t */\n"
"\tmsr sctlr_el1, x30\n"
"\tisb\n"
"\n"
"\t/* Disable trapping floating point access in EL1. */\n"
"\tmrs x30, cpacr_el1\n"
"\torr x30, x30, #(0x3 << 20)\n"
"\tmsr cpacr_el1, x30\n"
"\tisb\n"
"\n"
"\t/* Zero out the bss section. */\n"
"\tadr_l x29, bss_begin\n"
"\tadr_l x30, bss_end\n"
"0:\tcmp x29, x30\n"
"\tb.hs 1f\n"
"\tstp xzr, xzr, [x29], #16\n"
"\tb 0b\n"
"\n"
"1:\t/* Prepare the stack. */\n"
"\tadr_l x30, boot_stack_end\n"
"\tmov sp, x30\n"
"\n"
"\t/* Set up exception vector. */\n"
"\tadr x30, vector_table_el1\n"
"\tmsr vbar_el1, x30\n"
"\n"
"\t/* Call into Rust code. */\n"
"\tbl main\n"
"\n"
"\t/* Loop forever waiting for interrupts. */\n"
"2:\twfi\n"
"\tb 2b\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:595
msgid "`exceptions.S` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:599
msgid ""
"```armasm\n"
"/*\n"
" * Copyright 2023 Google LLC\n"
" *\n"
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
" * you may not use this file except in compliance with the License.\n"
" * You may obtain a copy of the License at\n"
" *\n"
" * https://www.apache.org/licenses/LICENSE-2.0\n"
" *\n"
" * Unless required by applicable law or agreed to in writing, software\n"
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
" * See the License for the specific language governing permissions and\n"
" * limitations under the License.\n"
" */\n"
"\n"
"/**\n"
" * Saves the volatile registers onto the stack. This currently takes 14\n"
" * instructions, so it can be used in exception handlers with 18 "
"instructions\n"
" * left.\n"
" *\n"
" * On return, x0 and x1 are initialised to elr_el2 and spsr_el2 "
"respectively,\n"
" * which can be used as the first and second arguments of a subsequent "
"call.\n"
" */\n"
".macro save_volatile_to_stack\n"
"\t/* Reserve stack space and save registers x0-x18, x29 & x30. */\n"
"\tstp x0, x1, [sp, #-(8 * 24)]!\n"
"\tstp x2, x3, [sp, #8 * 2]\n"
"\tstp x4, x5, [sp, #8 * 4]\n"
"\tstp x6, x7, [sp, #8 * 6]\n"
"\tstp x8, x9, [sp, #8 * 8]\n"
"\tstp x10, x11, [sp, #8 * 10]\n"
"\tstp x12, x13, [sp, #8 * 12]\n"
"\tstp x14, x15, [sp, #8 * 14]\n"
"\tstp x16, x17, [sp, #8 * 16]\n"
"\tstr x18, [sp, #8 * 18]\n"
"\tstp x29, x30, [sp, #8 * 20]\n"
"\n"
"\t/*\n"
"\t * Save elr_el1 & spsr_el1. This such that we can take nested exception\n"
"\t * and still be able to unwind.\n"
"\t */\n"
"\tmrs x0, elr_el1\n"
"\tmrs x1, spsr_el1\n"
"\tstp x0, x1, [sp, #8 * 22]\n"
".endm\n"
"\n"
"/**\n"
" * Restores the volatile registers from the stack. This currently takes 14\n"
" * instructions, so it can be used in exception handlers while still leaving "
"18\n"
" * instructions left; if paired with save_volatile_to_stack, there are 4\n"
" * instructions to spare.\n"
" */\n"
".macro restore_volatile_from_stack\n"
"\t/* Restore registers x2-x18, x29 & x30. */\n"
"\tldp x2, x3, [sp, #8 * 2]\n"
"\tldp x4, x5, [sp, #8 * 4]\n"
"\tldp x6, x7, [sp, #8 * 6]\n"
"\tldp x8, x9, [sp, #8 * 8]\n"
"\tldp x10, x11, [sp, #8 * 10]\n"
"\tldp x12, x13, [sp, #8 * 12]\n"
"\tldp x14, x15, [sp, #8 * 14]\n"
"\tldp x16, x17, [sp, #8 * 16]\n"
"\tldr x18, [sp, #8 * 18]\n"
"\tldp x29, x30, [sp, #8 * 20]\n"
"\n"
"\t/* Restore registers elr_el1 & spsr_el1, using x0 & x1 as scratch. */\n"
"\tldp x0, x1, [sp, #8 * 22]\n"
"\tmsr elr_el1, x0\n"
"\tmsr spsr_el1, x1\n"
"\n"
"\t/* Restore x0 & x1, and release stack space. */\n"
"\tldp x0, x1, [sp], #8 * 24\n"
".endm\n"
"\n"
"/**\n"
" * This is a generic handler for exceptions taken at the current EL while "
"using\n"
" * SP0. It behaves similarly to the SPx case by first switching to SPx, "
"doing\n"
" * the work, then switching back to SP0 before returning.\n"
" *\n"
" * Switching to SPx and calling the Rust handler takes 16 instructions. To\n"
" * restore and return we need an additional 16 instructions, so we can "
"implement\n"
" * the whole handler within the allotted 32 instructions.\n"
" */\n"
".macro current_exception_sp0 handler:req\n"
"\tmsr spsel, #1\n"
"\tsave_volatile_to_stack\n"
"\tbl \\handler\n"
"\trestore_volatile_from_stack\n"
"\tmsr spsel, #0\n"
"\teret\n"
".endm\n"
"\n"
"/**\n"
" * This is a generic handler for exceptions taken at the current EL while "
"using\n"
" * SPx. It saves volatile registers, calls the Rust handler, restores "
"volatile\n"
" * registers, then returns.\n"
" *\n"
" * This also works for exceptions taken from EL0, if we don't care about\n"
" * non-volatile registers.\n"
" *\n"
" * Saving state and jumping to the Rust handler takes 15 instructions, and\n"
" * restoring and returning also takes 15 instructions, so we can fit the "
"whole\n"
" * handler in 30 instructions, under the limit of 32.\n"
" */\n"
".macro current_exception_spx handler:req\n"
"\tsave_volatile_to_stack\n"
"\tbl \\handler\n"
"\trestore_volatile_from_stack\n"
"\teret\n"
".endm\n"
"\n"
".section .text.vector_table_el1, \"ax\"\n"
".global vector_table_el1\n"
".balign 0x800\n"
"vector_table_el1:\n"
"sync_cur_sp0:\n"
"\tcurrent_exception_sp0 sync_exception_current\n"
"\n"
".balign 0x80\n"
"irq_cur_sp0:\n"
"\tcurrent_exception_sp0 irq_current\n"
"\n"
".balign 0x80\n"
"fiq_cur_sp0:\n"
"\tcurrent_exception_sp0 fiq_current\n"
"\n"
".balign 0x80\n"
"serr_cur_sp0:\n"
"\tcurrent_exception_sp0 serr_current\n"
"\n"
".balign 0x80\n"
"sync_cur_spx:\n"
"\tcurrent_exception_spx sync_exception_current\n"
"\n"
".balign 0x80\n"
"irq_cur_spx:\n"
"\tcurrent_exception_spx irq_current\n"
"\n"
".balign 0x80\n"
"fiq_cur_spx:\n"
"\tcurrent_exception_spx fiq_current\n"
"\n"
".balign 0x80\n"
"serr_cur_spx:\n"
"\tcurrent_exception_spx serr_current\n"
"\n"
".balign 0x80\n"
"sync_lower_64:\n"
"\tcurrent_exception_spx sync_lower\n"
"\n"
".balign 0x80\n"
"irq_lower_64:\n"
"\tcurrent_exception_spx irq_lower\n"
"\n"
".balign 0x80\n"
"fiq_lower_64:\n"
"\tcurrent_exception_spx fiq_lower\n"
"\n"
".balign 0x80\n"
"serr_lower_64:\n"
"\tcurrent_exception_spx serr_lower\n"
"\n"
".balign 0x80\n"
"sync_lower_32:\n"
"\tcurrent_exception_spx sync_lower\n"
"\n"
".balign 0x80\n"
"irq_lower_32:\n"
"\tcurrent_exception_spx irq_lower\n"
"\n"
".balign 0x80\n"
"fiq_lower_32:\n"
"\tcurrent_exception_spx fiq_lower\n"
"\n"
".balign 0x80\n"
"serr_lower_32:\n"
"\tcurrent_exception_spx serr_lower\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:780
msgid "`idmap.S` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:784
msgid ""
"```armasm\n"
"/*\n"
" * Copyright 2023 Google LLC\n"
" *\n"
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
" * you may not use this file except in compliance with the License.\n"
" * You may obtain a copy of the License at\n"
" *\n"
" * https://www.apache.org/licenses/LICENSE-2.0\n"
" *\n"
" * Unless required by applicable law or agreed to in writing, software\n"
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
" * See the License for the specific language governing permissions and\n"
" * limitations under the License.\n"
" */\n"
"\n"
".set .L_TT_TYPE_BLOCK, 0x1\n"
".set .L_TT_TYPE_PAGE, 0x3\n"
".set .L_TT_TYPE_TABLE, 0x3\n"
"\n"
"/* Access flag. */\n"
".set .L_TT_AF, 0x1 << 10\n"
"/* Not global. */\n"
".set .L_TT_NG, 0x1 << 11\n"
".set .L_TT_XN, 0x3 << 53\n"
"\n"
".set .L_TT_MT_DEV, 0x0 << 2\t\t\t// MAIR #0 (DEV_nGnRE)\n"
".set .L_TT_MT_MEM, (0x1 << 2) | (0x3 << 8)\t// MAIR #1 (MEM_WBWA), inner "
"shareable\n"
"\n"
".set .L_BLOCK_DEV, .L_TT_TYPE_BLOCK | .L_TT_MT_DEV | .L_TT_AF | .L_TT_XN\n"
".set .L_BLOCK_MEM, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG\n"
"\n"
".section \".rodata.idmap\", \"a\", %progbits\n"
".global idmap\n"
".align 12\n"
"idmap:\n"
"\t/* level 1 */\n"
"\t.quad\t\t.L_BLOCK_DEV | 0x0\t\t // 1 GiB of device mappings\n"
"\t.quad\t\t.L_BLOCK_MEM | 0x40000000\t// 1 GiB of DRAM\n"
"\t.fill\t\t254, 8, 0x0\t\t\t// 254 GiB of unmapped VA space\n"
"\t.quad\t\t.L_BLOCK_DEV | 0x4000000000 // 1 GiB of device mappings\n"
"\t.fill\t\t255, 8, 0x0\t\t\t// 255 GiB of remaining VA space\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:829
msgid "`image.ld` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:833
msgid ""
"```ld\n"
"/*\n"
" * Copyright 2023 Google LLC\n"
" *\n"
" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
" * you may not use this file except in compliance with the License.\n"
" * You may obtain a copy of the License at\n"
" *\n"
" * https://www.apache.org/licenses/LICENSE-2.0\n"
" *\n"
" * Unless required by applicable law or agreed to in writing, software\n"
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
" * See the License for the specific language governing permissions and\n"
" * limitations under the License.\n"
" */\n"
"\n"
"/*\n"
" * Code will start running at this symbol which is placed at the start of "
"the\n"
" * image.\n"
" */\n"
"ENTRY(entry)\n"
"\n"
"MEMORY\n"
"{\n"
"\timage : ORIGIN = 0x40080000, LENGTH = 2M\n"
"}\n"
"\n"
"SECTIONS\n"
"{\n"
"\t/*\n"
"\t * Collect together the code.\n"
"\t */\n"
"\t.init : ALIGN(4096) {\n"
"\t\ttext_begin = .;\n"
"\t\t*(.init.entry)\n"
"\t\t*(.init.*)\n"
"\t} >image\n"
"\t.text : {\n"
"\t\t*(.text.*)\n"
"\t} >image\n"
"\ttext_end = .;\n"
"\n"
"\t/*\n"
"\t * Collect together read-only data.\n"
"\t */\n"
"\t.rodata : ALIGN(4096) {\n"
"\t\trodata_begin = .;\n"
"\t\t*(.rodata.*)\n"
"\t} >image\n"
"\t.got : {\n"
"\t\t*(.got)\n"
"\t} >image\n"
"\trodata_end = .;\n"
"\n"
"\t/*\n"
"\t * Collect together the read-write data including .bss at the end which\n"
"\t * will be zero'd by the entry code.\n"
"\t */\n"
"\t.data : ALIGN(4096) {\n"
"\t\tdata_begin = .;\n"
"\t\t*(.data.*)\n"
"\t\t/*\n"
"\t\t * The entry point code assumes that .data is a multiple of 32\n"
"\t\t * bytes long.\n"
"\t\t */\n"
"\t\t. = ALIGN(32);\n"
"\t\tdata_end = .;\n"
"\t} >image\n"
"\n"
"\t/* Everything beyond this point will not be included in the binary. */\n"
"\tbin_end = .;\n"
"\n"
"\t/* The entry point code assumes that .bss is 16-byte aligned. */\n"
"\t.bss : ALIGN(16) {\n"
"\t\tbss_begin = .;\n"
"\t\t*(.bss.*)\n"
"\t\t*(COMMON)\n"
"\t\t. = ALIGN(16);\n"
"\t\tbss_end = .;\n"
"\t} >image\n"
"\n"
"\t.stack (NOLOAD) : ALIGN(4096) {\n"
"\t\tboot_stack_begin = .;\n"
"\t\t. += 40 * 4096;\n"
"\t\t. = ALIGN(4096);\n"
"\t\tboot_stack_end = .;\n"
"\t} >image\n"
"\n"
"\t. = ALIGN(4K);\n"
"\tPROVIDE(dma_region = .);\n"
"\n"
"\t/*\n"
"\t * Remove unused sections from the image.\n"
"\t */\n"
"\t/DISCARD/ : {\n"
"\t\t/* The image loads itself so doesn't need these sections. */\n"
"\t\t*(.gnu.hash)\n"
"\t\t*(.hash)\n"
"\t\t*(.interp)\n"
"\t\t*(.eh_frame_hdr)\n"
"\t\t*(.eh_frame)\n"
"\t\t*(.note.gnu.build-id)\n"
"\t}\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:940
msgid "`Makefile` (you shouldn't need to change this):"
msgstr ""
#: src/exercises/bare-metal/rtc.md:944
msgid ""
"```makefile\n"
"# Copyright 2023 Google LLC\n"
"#\n"
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"# you may not use this file except in compliance with the License.\n"
"# You may obtain a copy of the License at\n"
"#\n"
"# http://www.apache.org/licenses/LICENSE-2.0\n"
"#\n"
"# Unless required by applicable law or agreed to in writing, software\n"
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"# See the License for the specific language governing permissions and\n"
"# limitations under the License.\n"
"\n"
"UNAME := $(shell uname -s)\n"
"ifeq ($(UNAME),Linux)\n"
"\tTARGET = aarch64-linux-gnu\n"
"else\n"
"\tTARGET = aarch64-none-elf\n"
"endif\n"
"OBJCOPY = $(TARGET)-objcopy\n"
"\n"
".PHONY: build qemu_minimal qemu qemu_logger\n"
"\n"
"all: rtc.bin\n"
"\n"
"build:\n"
"\tcargo build\n"
"\n"
"rtc.bin: build\n"
"\t$(OBJCOPY) -O binary target/aarch64-unknown-none/debug/rtc $@\n"
"\n"
"qemu: rtc.bin\n"
"\tqemu-system-aarch64 -machine virt,gic-version=3 -cpu max -serial mon:stdio "
"-display none -kernel $< -s\n"
"\n"
"clean:\n"
"\tcargo clean\n"
"\trm -f *.bin\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:989
msgid ""
"```toml\n"
"[build]\n"
"target = \"aarch64-unknown-none\"\n"
"rustflags = [\"-C\", \"link-arg=-Timage.ld\"]\n"
"```"
msgstr ""
#: src/exercises/bare-metal/rtc.md:995
msgid "Run the code in QEMU with `make qemu`."
msgstr ""
#: src/concurrency.md:1
#, fuzzy
msgid "Welcome to Concurrency in Rust"
msgstr "Welcome to Comprehensive Rust 🦀"
#: src/concurrency.md:3
msgid ""
"Rust has full support for concurrency using OS threads with mutexes and "
"channels."
msgstr ""
"러스트는 동시성 지원이 막강합니다. 운영체제 레벨의 스레드를 사용하며, 뮤택스"
"와 채널도 지원합니다."
#: src/concurrency.md:6
msgid ""
"The Rust type system plays an important role in making many concurrency bugs "
"compile time bugs. This is often referred to as _fearless concurrency_ since "
"you can rely on the compiler to ensure correctness at runtime."
msgstr ""
"러스트의 타입 시스템은 프로그램에 동시성 버그가 있을 경우, 컴파일 시에 에러"
"가 발생하도록 해 줍니다. 컴파일러를 이용해서 프로그램이 수행시에 정확히 동작"
"함을 미리 보장해 주기 때문에, 사람들은 이를 종종 _겁없는 동시성_ 이라고 합니"
"다."
#: src/concurrency/threads.md:3
msgid "Rust threads work similarly to threads in other languages:"
msgstr "러스트의 스레드는 다른 언어의 스레드와 유사하게 동작합니다:"
#: src/concurrency/threads.md:5
msgid ""
"```rust,editable\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"fn main() {\n"
" thread::spawn(|| {\n"
" for i in 1..10 {\n"
" println!(\"Count in thread: {i}!\");\n"
" thread::sleep(Duration::from_millis(5));\n"
" }\n"
" });\n"
"\n"
" for i in 1..5 {\n"
" println!(\"Main thread: {i}\");\n"
" thread::sleep(Duration::from_millis(5));\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"fn main() {\n"
" thread::spawn(|| {\n"
" for i in 1..10 {\n"
" println!(\"Count in thread: {i}!\");\n"
" thread::sleep(Duration::from_millis(5));\n"
" }\n"
" });\n"
"\n"
" for i in 1..5 {\n"
" println!(\"Main thread: {i}\");\n"
" thread::sleep(Duration::from_millis(5));\n"
" }\n"
"}\n"
"```"
#: src/concurrency/threads.md:24
msgid "Threads are all daemon threads, the main thread does not wait for them."
msgstr ""
"스레드는 모두 데몬 스레드입니다. 따라서 메인 스레드는 이 스레드들이 끝나기를 "
"기다리지 않습니다."
#: src/concurrency/threads.md:25
msgid "Thread panics are independent of each other."
msgstr "한 스레드에서 발생한 패닉은 다른 스레드에게 영향을 끼치지 않습니다."
#: src/concurrency/threads.md:26
msgid "Panics can carry a payload, which can be unpacked with `downcast_ref`."
msgstr ""
"패닉은 추가정보(페이로드)를 포함할 수 있으며, 이는 `downcast_ref`로 풀어볼 "
"수 있습니다."
#: src/concurrency/threads.md:32
msgid ""
"Notice that the thread is stopped before it reaches 10 — the main thread is "
"not waiting."
msgstr ""
"메인 스레드가 자식 스레드를 기다리지 않기 때문에 자식 스레드의 for문은 10까"
"지 가지 않습니다."
#: src/concurrency/threads.md:35
msgid ""
"Use `let handle = thread::spawn(...)` and later `handle.join()` to wait for "
"the thread to finish."
msgstr ""
"만약 메인 스레드가 자식 스레드가 끝날 때 까지 기다리기를 원한다면 `let "
"handle = thread::spawn(...)`으로 스레드를 선언한 후 `handle.join()`로 연결하"
"여 사용합니다."
#: src/concurrency/threads.md:38
msgid "Trigger a panic in the thread, notice how this doesn't affect `main`."
msgstr ""
"자식 스레드에서 발생한 패닉이 메인 스레드에는 영향을 주지 않음을 확인하시기 "
"바랍니다."
#: src/concurrency/threads.md:40
msgid ""
"Use the `Result` return value from `handle.join()` to get access to the "
"panic payload. This is a good time to talk about [`Any`](https://doc.rust-"
"lang.org/std/any/index.html)."
msgstr ""
"`handle.join()`사용시 `Result` 반환값을 통해 패닉의 추가정보에 접근할 수 있습"
"니다. 이 시점에서 [`Any`](https://doc.rust-lang.org/std/any/index.html)에 대"
"해 이야기를 해 보면 좋습니다."
#: src/concurrency/scoped-threads.md:3
msgid "Normal threads cannot borrow from their environment:"
msgstr "보통, 스레드는 스레드 밖에서 데이터를 빌릴 수 없습니다:"
#: src/concurrency/scoped-threads.md:5
#, fuzzy
msgid ""
"```rust,editable,compile_fail\n"
"use std::thread;\n"
"\n"
"fn foo() {\n"
" let s = String::from(\"Hello\");\n"
" thread::spawn(|| {\n"
" println!(\"Length: {}\", s.len());\n"
" });\n"
"}\n"
"\n"
"fn main() {\n"
" foo();\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let s = String::from(\"Hello\");\n"
"\n"
" thread::spawn(|| {\n"
" println!(\"Length: {}\", s.len());\n"
" });\n"
"}\n"
"```"
#: src/concurrency/scoped-threads.md:20
msgid ""
"However, you can use a [scoped thread](https://doc.rust-lang.org/std/thread/"
"fn.scope.html) for this:"
msgstr ""
"하지만, [scoped thread](https://doc.rust-lang.org/std/thread/fn.scope.html)에"
"서는 가능합니다:"
#: src/concurrency/scoped-threads.md:22
msgid ""
"```rust,editable\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let s = String::from(\"Hello\");\n"
"\n"
" thread::scope(|scope| {\n"
" scope.spawn(|| {\n"
" println!(\"Length: {}\", s.len());\n"
" });\n"
" });\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let s = String::from(\"Hello\");\n"
"\n"
" thread::scope(|scope| {\n"
" scope.spawn(|| {\n"
" println!(\"Length: {}\", s.len());\n"
" });\n"
" });\n"
"}\n"
"```"
#: src/concurrency/scoped-threads.md:40
msgid ""
"The reason for that is that when the `thread::scope` function completes, all "
"the threads are guaranteed to be joined, so they can return borrowed data."
msgstr ""
"`thread::scope` 함수가 완료되면 그 안에서 생성된 모든 스레드들이 종료했음이 "
"보장되기 때문에, 그 때 빌렸던 데이터들을 다시 반환할 수 있기 때문입니다."
#: src/concurrency/scoped-threads.md:41
msgid ""
"Normal Rust borrowing rules apply: you can either borrow mutably by one "
"thread, or immutably by any number of threads."
msgstr ""
"일반적인 러스트의 빌림 규칙이 적용됩니다: 한 스레드에 의한 가변 빌림 또는 여"
"러 스레드에 대한 불변 빌림중 하나만 가능합니다."
#: src/concurrency/channels.md:3
msgid ""
"Rust channels have two parts: a `Sender<T>` and a `Receiver<T>`. The two "
"parts are connected via the channel, but you only see the end-points."
msgstr ""
"러스트의 채널은 `Sender<T>` 와 `Receiver<T>` 두 부분으로 구성됩니다. 이 둘은 "
"채널을 통해 서로 연결되어 있지만, 우리는 채널을 볼 수는 없고 이 양 끝단만을 "
"사용하게 됩니다."
#: src/concurrency/channels.md:6
msgid ""
"```rust,editable\n"
"use std::sync::mpsc;\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let (tx, rx) = mpsc::channel();\n"
"\n"
" tx.send(10).unwrap();\n"
" tx.send(20).unwrap();\n"
"\n"
" println!(\"Received: {:?}\", rx.recv());\n"
" println!(\"Received: {:?}\", rx.recv());\n"
"\n"
" let tx2 = tx.clone();\n"
" tx2.send(30).unwrap();\n"
" println!(\"Received: {:?}\", rx.recv());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::sync::mpsc;\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let (tx, rx) = mpsc::channel();\n"
"\n"
" tx.send(10).unwrap();\n"
" tx.send(20).unwrap();\n"
"\n"
" println!(\"Received: {:?}\", rx.recv());\n"
" println!(\"Received: {:?}\", rx.recv());\n"
"\n"
" let tx2 = tx.clone();\n"
" tx2.send(30).unwrap();\n"
" println!(\"Received: {:?}\", rx.recv());\n"
"}\n"
"```"
#: src/concurrency/channels.md:27
msgid ""
"`mpsc` stands for Multi-Producer, Single-Consumer. `Sender` and `SyncSender` "
"implement `Clone` (so you can make multiple producers) but `Receiver` does "
"not."
msgstr ""
"`mpsc`는 “Multi-Produce, Single-Consumer”를 의미합니다. `Sender`와 "
"`SyncSender`는 `Clone`을 구현하지만 (즉, 여러개의 producer를 만들수 있습니"
"다) `Receiver`는 `Clone`을 구현하지 않습니다."
#: src/concurrency/channels.md:29
msgid ""
"`send()` and `recv()` return `Result`. If they return `Err`, it means the "
"counterpart `Sender` or `Receiver` is dropped and the channel is closed."
msgstr ""
"`send()`와 `recv()`는 `Result`를 반환합니다. 만일 `Err`가 반환된다면, 상대방"
"의 `Sender`또는 `Receiver`가 삭제되었고 채널이 닫혔다는 뜻입니다."
#: src/concurrency/channels/unbounded.md:3
msgid "You get an unbounded and asynchronous channel with `mpsc::channel()`:"
msgstr "`mpsc::channel()` 함수는 경계가 없는 비동기 채널을 생성합니다:"
#: src/concurrency/channels/unbounded.md:5
msgid ""
"```rust,editable\n"
"use std::sync::mpsc;\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"fn main() {\n"
" let (tx, rx) = mpsc::channel();\n"
"\n"
" thread::spawn(move || {\n"
" let thread_id = thread::current().id();\n"
" for i in 1..10 {\n"
" tx.send(format!(\"Message {i}\")).unwrap();\n"
" println!(\"{thread_id:?}: sent Message {i}\");\n"
" }\n"
" println!(\"{thread_id:?}: done\");\n"
" });\n"
" thread::sleep(Duration::from_millis(100));\n"
"\n"
" for msg in rx.iter() {\n"
" println!(\"Main: got {msg}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::sync::mpsc;\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"fn main() {\n"
" let (tx, rx) = mpsc::channel();\n"
"\n"
" thread::spawn(move || {\n"
" let thread_id = thread::current().id();\n"
" for i in 1..10 {\n"
" tx.send(format!(\"Message {i}\")).unwrap();\n"
" println!(\"{thread_id:?}: sent Message {i}\");\n"
" }\n"
" println!(\"{thread_id:?}: done\");\n"
" });\n"
" thread::sleep(Duration::from_millis(100));\n"
"\n"
" for msg in rx.iter() {\n"
" println!(\"Main: got {msg}\");\n"
" }\n"
"}\n"
"```"
#: src/concurrency/channels/bounded.md:3
#, fuzzy
msgid ""
"With bounded (synchronous) channels, `send` can block the current thread:"
msgstr "경계가 있는 동기 채널은 `send`가 현제 스레드를 블로킹 하도록 만듭니다:"
#: src/concurrency/channels/bounded.md:5
msgid ""
"```rust,editable\n"
"use std::sync::mpsc;\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"fn main() {\n"
" let (tx, rx) = mpsc::sync_channel(3);\n"
"\n"
" thread::spawn(move || {\n"
" let thread_id = thread::current().id();\n"
" for i in 1..10 {\n"
" tx.send(format!(\"Message {i}\")).unwrap();\n"
" println!(\"{thread_id:?}: sent Message {i}\");\n"
" }\n"
" println!(\"{thread_id:?}: done\");\n"
" });\n"
" thread::sleep(Duration::from_millis(100));\n"
"\n"
" for msg in rx.iter() {\n"
" println!(\"Main: got {msg}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::sync::mpsc;\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"fn main() {\n"
" let (tx, rx) = mpsc::sync_channel(3);\n"
"\n"
" thread::spawn(move || {\n"
" let thread_id = thread::current().id();\n"
" for i in 1..10 {\n"
" tx.send(format!(\"Message {i}\")).unwrap();\n"
" println!(\"{thread_id:?}: sent Message {i}\");\n"
" }\n"
" println!(\"{thread_id:?}: done\");\n"
" });\n"
" thread::sleep(Duration::from_millis(100));\n"
"\n"
" for msg in rx.iter() {\n"
" println!(\"Main: got {msg}\");\n"
" }\n"
"}\n"
"```"
#: src/concurrency/channels/bounded.md:31
msgid ""
"Calling `send` will block the current thread until there is space in the "
"channel for the new message. The thread can be blocked indefinitely if there "
"is nobody who reads from the channel."
msgstr ""
#: src/concurrency/channels/bounded.md:32
msgid ""
"A call to `send` will abort with an error (that is why it returns `Result`) "
"if the channel is closed. A channel is closed when the receiver is dropped."
msgstr ""
#: src/concurrency/channels/bounded.md:33
msgid ""
"A bounded channel with a size of zero is called a \"rendezvous channel\". "
"Every send will block the current thread until another thread calls `read`."
msgstr ""
#: src/concurrency/send-sync.md:1
msgid "`Send` and `Sync`"
msgstr "`Send`와 `Sync`"
#: src/concurrency/send-sync.md:3
msgid ""
"How does Rust know to forbid shared access across thread? The answer is in "
"two traits:"
msgstr ""
"러스트는 어떻게 해서 스레드 간에 특정 데이터 타입이 공유될 수 있거나, 안된다"
"는 것을 알까요? 정답은 다음 두 트레잇에 있습니다:"
#: src/concurrency/send-sync.md:5
msgid ""
"[`Send`](https://doc.rust-lang.org/std/marker/trait.Send.html): a type `T` "
"is `Send` if it is safe to move a `T` across a thread boundary."
msgstr ""
"[`Send`](https://doc.rust-lang.org/std/marker/trait.Send.html): `T`가 스레드 "
"간 이동이 안전하다면, `T`의 타입은 `Send`입니다."
#: src/concurrency/send-sync.md:7
msgid ""
"[`Sync`](https://doc.rust-lang.org/std/marker/trait.Sync.html): a type `T` "
"is `Sync` if it is safe to move a `&T` across a thread boundary."
msgstr ""
"[`Sync`](https://doc.rust-lang.org/std/marker/trait.Sync.html): `&T`가 스레"
"드 간 이동이 안전하다면, `&T`의 타입은 `Sync`입니다."
#: src/concurrency/send-sync.md:10
msgid ""
"`Send` and `Sync` are [unsafe traits](../unsafe/unsafe-traits.md). The "
"compiler will automatically derive them for your types as long as they only "
"contain `Send` and `Sync` types. You can also implement them manually when "
"you know it is valid."
msgstr ""
"`Send`와 `Sync` 트레잇은 [안전하지 않은 트레잇](../unsafe/unsafe-traits.md)입"
"니다. 컴파일러는 타입의 요소들이 모두 `Send`와 `Sync` 타입이면 자동으로 이 트"
"레잇들을 적용시켜 줍니다. 물론 여러분 스스로 맞다고 알고 있다면 직접 구현해"
"도 됩니다."
#: src/concurrency/send-sync.md:20
msgid ""
"One can think of these traits as markers that the type has certain thread-"
"safety properties."
msgstr ""
"`Sync`와 `Send`는 어떤 타입이 특정한 스레드-안전 속성을 가짐을 나타내는 마커"
"로 생각할 수 있습니다."
#: src/concurrency/send-sync.md:21
msgid "They can be used in the generic constraints as normal traits."
msgstr ""
"이 두 트레이트는 제너릭에서 제약 조건을 나타내는 트레이트로 사용될 수도 있습"
"니다."
#: src/concurrency/send-sync/send.md:1
msgid "`Send`"
msgstr "`Send`"
#: src/concurrency/send-sync/send.md:3
msgid ""
"A type `T` is [`Send`](https://doc.rust-lang.org/std/marker/trait.Send.html) "
"if it is safe to move a `T` value to another thread."
msgstr ""
"`T`가 스레드 간에 안전하게 이동될 수 있다면, `T`의 타입은 `Send`입니다."
#: src/concurrency/send-sync/send.md:5
msgid ""
"The effect of moving ownership to another thread is that _destructors_ will "
"run in that thread. So the question is when you can allocate a value in one "
"thread and deallocate it in another."
msgstr ""
"소유권을 다른 스레드로 이동하면 소멸자가 해당 스레드에서 실행됩니다. 여기서 "
"의문은 \"언제 한 스레드에서 값을 할당하고 다른 스레드에서 값을 할당 해제할 "
"수 있는가\" 입니다."
#: src/concurrency/send-sync/send.md:13
msgid ""
"As an example, a connection to the SQLite library must only be accessed from "
"a single thread."
msgstr ""
"예를 들어 SQLite 라이브러리 연결은 단일 스레드에서만 액세스해야 합니다."
#: src/concurrency/send-sync/sync.md:1
msgid "`Sync`"
msgstr "`Sync`"
#: src/concurrency/send-sync/sync.md:3
msgid ""
"A type `T` is [`Sync`](https://doc.rust-lang.org/std/marker/trait.Sync.html) "
"if it is safe to access a `T` value from multiple threads at the same time."
msgstr ""
"`&T`가 여러 스레드에서 안전하게 접근될 수 있다면, `&T`의 타입은 `Sync`입니다."
#: src/concurrency/send-sync/sync.md:6
msgid "More precisely, the definition is:"
msgstr "좀 더 정확한 정의는 다음과 같습니다:"
#: src/concurrency/send-sync/sync.md:8
msgid "`T` is `Sync` if and only if `&T` is `Send`"
msgstr "`&T`가 `Send`인 경우에만 `T`의 타입이 `Sync`가 됩니다"
#: src/concurrency/send-sync/sync.md:14
msgid ""
"This statement is essentially a shorthand way of saying that if a type is "
"thread-safe for shared use, it is also thread-safe to pass references of it "
"across threads."
msgstr ""
"위 문장을 풀어서 이야기 하면, 어떤 타입이 스레드 간에 공유되어서 사용되기에 "
"안전하다면 그 타입의 참조 타입은 스레드 간에 이동 가능하다는 것입니다."
#: src/concurrency/send-sync/sync.md:16
msgid ""
"This is because if a type is Sync it means that it can be shared across "
"multiple threads without the risk of data races or other synchronization "
"issues, so it is safe to move it to another thread. A reference to the type "
"is also safe to move to another thread, because the data it references can "
"be accessed from any thread safely."
msgstr ""
"이는 다음과 같이 증명할 수 있습니다: 어떤 타입이 `Sync`라는 말은 곧 그 타입"
"이 여러 스레드들 사이에서 데이터 레이스나 여타 동기화 문제 없이 공유 가능하다"
"는 말입니다. 스레드 간 공유가 안전하다면, 스레드간 이동도 안전할 수 밖에 없습"
"니다. 어떤 타입의 스레드간 이동이 안전하다면, 그 타입의 참조 또한 스레드간 이"
"동이 안전할 수 밖에 없습니다."
#: src/concurrency/send-sync/examples.md:3
msgid "`Send + Sync`"
msgstr "`Send + Sync`"
#: src/concurrency/send-sync/examples.md:5
msgid "Most types you come across are `Send + Sync`:"
msgstr "여러분이 다루게 될 대부분의 타입은 `Send + Sync`입니다:"
#: src/concurrency/send-sync/examples.md:7
msgid "`i8`, `f32`, `bool`, `char`, `&str`, ..."
msgstr "`i8`, `f32`, `bool`, `char`, `&str`, ..."
#: src/concurrency/send-sync/examples.md:8
msgid "`(T1, T2)`, `[T; N]`, `&[T]`, `struct { x: T }`, ..."
msgstr "`(T1, T2)`, `[T; N]`, `&[T]`, `struct { x: T }`, ..."
#: src/concurrency/send-sync/examples.md:9
msgid "`String`, `Option<T>`, `Vec<T>`, `Box<T>`, ..."
msgstr "`String`, `Option<T>`, `Vec<T>`, `Box<T>`, ..."
#: src/concurrency/send-sync/examples.md:10
msgid "`Arc<T>`: Explicitly thread-safe via atomic reference count."
msgstr "`Arc<T>`: 참조 카운트 조작을 아토믹 하기 때문에 스레드 안전함."
#: src/concurrency/send-sync/examples.md:11
msgid "`Mutex<T>`: Explicitly thread-safe via internal locking."
msgstr ""
"`Mutex<T>`: 값을 접근하기 위해 뮤택스를 잠궈야 하기 때문에 스레드 안전함."
#: src/concurrency/send-sync/examples.md:12
msgid "`AtomicBool`, `AtomicU8`, ...: Uses special atomic instructions."
msgstr ""
"`AtomicBool`, `AtomicU8`, ...: 값을 접근할 때 특별한 아토믹 명령어들을 사용합"
"니다."
#: src/concurrency/send-sync/examples.md:14
msgid ""
"The generic types are typically `Send + Sync` when the type parameters are "
"`Send + Sync`."
msgstr ""
"제네릭 타입은 일반적으로 타입 파라메터가 `Send + Sync`이면 `Send + Sync` 입니"
"다."
#: src/concurrency/send-sync/examples.md:17
msgid "`Send + !Sync`"
msgstr "`Send + !Sync`"
#: src/concurrency/send-sync/examples.md:19
msgid ""
"These types can be moved to other threads, but they're not thread-safe. "
"Typically because of interior mutability:"
msgstr ""
"아래 타입들은 다른 스레드로 이동될 수 있지만 내부적으로 값이 변경될 수 있기 "
"때문에 스레드 안전하지 않습니다:"
#: src/concurrency/send-sync/examples.md:22
msgid "`mpsc::Sender<T>`"
msgstr "`mpsc::Sender<T>`"
#: src/concurrency/send-sync/examples.md:23
msgid "`mpsc::Receiver<T>`"
msgstr "`mpsc::Receiver<T>`"
#: src/concurrency/send-sync/examples.md:24
msgid "`Cell<T>`"
msgstr "`Cell<T>`"
#: src/concurrency/send-sync/examples.md:25
msgid "`RefCell<T>`"
msgstr "`RefCell<T>`"
#: src/concurrency/send-sync/examples.md:27
msgid "`!Send + Sync`"
msgstr "`!Send + Sync`"
#: src/concurrency/send-sync/examples.md:29
msgid ""
"These types are thread-safe, but they cannot be moved to another thread:"
msgstr "아래 타입들은 스레드 안전하지만 다른 스레드로 이동될 수 없습니다:"
#: src/concurrency/send-sync/examples.md:31
msgid ""
"`MutexGuard<T>`: Uses OS level primitives which must be deallocated on the "
"thread which created them."
msgstr ""
"`MutexGuard<T>`: 내부적으로, 운영체제가 제공하는 primitive를 사용하는데, 이 "
"primitive는 생성된 스레드에서 해제가 이루어져야 합니다. (_역주_: 그래서 다른 "
"스레드로 옮길 수 없습니다.)"
#: src/concurrency/send-sync/examples.md:34
msgid "`!Send + !Sync`"
msgstr "`!Send + !Sync`"
#: src/concurrency/send-sync/examples.md:36
msgid "These types are not thread-safe and cannot be moved to other threads:"
msgstr ""
"아래 타입들은 스레드 안전하지도 않고 다른 스레드로 이동될 수도 없습니다:"
#: src/concurrency/send-sync/examples.md:38
msgid ""
"`Rc<T>`: each `Rc<T>` has a reference to an `RcBox<T>`, which contains a non-"
"atomic reference count."
msgstr ""
"`Rc<T>`: `Rc<T>` 는 아토믹하지 않은 방식으로 참조 카운트를 조작하는 "
"`RcBox<T>`를 참조합니다."
#: src/concurrency/send-sync/examples.md:40
msgid ""
"`*const T`, `*mut T`: Rust assumes raw pointers may have special concurrency "
"considerations."
msgstr ""
"`*const T`, `*mut T`: 러스트는 포인터가 스레드 안전하지 않다고 가정합니다."
#: src/concurrency/shared_state.md:3
msgid ""
"Rust uses the type system to enforce synchronization of shared data. This is "
"primarily done via two types:"
msgstr ""
"러스트는 주로 아래 두 가지 타입을 이용해서 공유 데이터 동기화를 수행합니다:"
#: src/concurrency/shared_state.md:6
msgid ""
"[`Arc<T>`](https://doc.rust-lang.org/std/sync/struct.Arc.html), atomic "
"reference counted `T`: handles sharing between threads and takes care to "
"deallocate `T` when the last reference is dropped,"
msgstr ""
"[`Arc<T>`](https://doc.rust-lang.org/std/sync/struct.Arc.html), `T`에 대한 아"
"토믹 참조 카운트: 이 참조는 다수의 스레드 사이에서 공유될 수 있고, 참조하던 "
"마지막 스레드가 종료할 경우 `T`를 반환합니다."
#: src/concurrency/shared_state.md:8
msgid ""
"[`Mutex<T>`](https://doc.rust-lang.org/std/sync/struct.Mutex.html): ensures "
"mutually exclusive access to the `T` value."
msgstr ""
"[`Mutex<T>`](https://doc.rust-lang.org/std/sync/struct.Mutex.html): `T`값에 "
"대한 상호 배제 엑세스를 보장합니다."
#: src/concurrency/shared_state/arc.md:1
msgid "`Arc`"
msgstr "`Arc`"
#: src/concurrency/shared_state/arc.md:3
#, fuzzy
msgid ""
"[`Arc<T>`](https://doc.rust-lang.org/std/sync/struct.Arc.html) allows shared "
"read-only access via `Arc::clone`:"
msgstr ""
"[`Arc<T>`](https://doc.rust-lang.org/std/sync/struct.Arc.html)의 `clone` 메서"
"드를 이용하면 여러 스레드가 한 데이터를 동시에 (_역주_: 그리고 안전하게. 스레"
"드가 하나라도 살아있는 동안에는 `T`가 반환되지 않음) 읽을 수 있습니다:"
#: src/concurrency/shared_state/arc.md:5
msgid ""
"```rust,editable\n"
"use std::thread;\n"
"use std::sync::Arc;\n"
"\n"
"fn main() {\n"
" let v = Arc::new(vec![10, 20, 30]);\n"
" let mut handles = Vec::new();\n"
" for _ in 1..5 {\n"
" let v = Arc::clone(&v);\n"
" handles.push(thread::spawn(move || {\n"
" let thread_id = thread::current().id();\n"
" println!(\"{thread_id:?}: {v:?}\");\n"
" }));\n"
" }\n"
"\n"
" handles.into_iter().for_each(|h| h.join().unwrap());\n"
" println!(\"v: {v:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::thread;\n"
"use std::sync::Arc;\n"
"\n"
"fn main() {\n"
" let v = Arc::new(vec![10, 20, 30]);\n"
" let mut handles = Vec::new();\n"
" for _ in 1..5 {\n"
" let v = Arc::clone(&v);\n"
" handles.push(thread::spawn(move || {\n"
" let thread_id = thread::current().id();\n"
" println!(\"{thread_id:?}: {v:?}\");\n"
" }));\n"
" }\n"
"\n"
" handles.into_iter().for_each(|h| h.join().unwrap());\n"
" println!(\"v: {v:?}\");\n"
"}\n"
"```"
#: src/concurrency/shared_state/arc.md:29
#, fuzzy
msgid ""
"`Arc` stands for \"Atomic Reference Counted\", a thread safe version of `Rc` "
"that uses atomic operations."
msgstr ""
"`Arc`는 \"Atomic Reference Counted\"를 의미하며, 스레드 안정성을 보장하는 "
"`Rc`라고 생각하면 됩니다."
#: src/concurrency/shared_state/arc.md:31
#, fuzzy
msgid ""
"`Arc<T>` implements `Clone` whether or not `T` does. It implements `Send` "
"and `Sync` if and only if `T` implements them both."
msgstr ""
"`T`가 `Clone`을 구현하든 안하든 `Arc<T>`는 `Clone`을 구현합니다. `Send`와 "
"`Sync`는 `T`가 이들을 구현하는 경우에만 구현됩니다."
#: src/concurrency/shared_state/arc.md:33
#, fuzzy
msgid ""
"`Arc::clone()` has the cost of atomic operations that get executed, but "
"after that the use of the `T` is free."
msgstr ""
"`Arc::clone()`는 아토믹 연산을 수행하기 때문에 그 때 코스트가 좀 있지만, 일"
"단 `clone()`이 끝난 후 `T`를 사용하는 대에는 아무런 오버헤드가 없습니다."
#: src/concurrency/shared_state/arc.md:35
#, fuzzy
msgid ""
"Beware of reference cycles, `Arc` does not use a garbage collector to detect "
"them."
msgstr ""
"순환 참조가 발생하지 않도록 주의해야 합니다. 러스트는 순환 참조를 감지하는 가"
"비지 컬랙터가 없습니다."
#: src/concurrency/shared_state/arc.md:36
#, fuzzy
msgid "`std::sync::Weak` can help."
msgstr "순환 참조를 피하는데 `std::sync::Weak`가 도움이 될 것입니다."
#: src/concurrency/shared_state/mutex.md:1
msgid "`Mutex`"
msgstr "`Mutex`"
#: src/concurrency/shared_state/mutex.md:3
msgid ""
"[`Mutex<T>`](https://doc.rust-lang.org/std/sync/struct.Mutex.html) ensures "
"mutual exclusion _and_ allows mutable access to `T` behind a read-only "
"interface:"
msgstr ""
"[`Mutex<T>`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)를 이용하"
"면 불변 참조를 통해서도 `T`의 값을 수정할 수가 있으며, _이에 더해서_ 한 번에 "
"한 스레드만 `T`의 값을 접근(읽거나 쓰거나)함을 보장해 줍니다:"
#: src/concurrency/shared_state/mutex.md:6
msgid ""
"```rust,editable\n"
"use std::sync::Mutex;\n"
"\n"
"fn main() {\n"
" let v = Mutex::new(vec![10, 20, 30]);\n"
" println!(\"v: {:?}\", v.lock().unwrap());\n"
"\n"
" {\n"
" let mut guard = v.lock().unwrap();\n"
" guard.push(40);\n"
" }\n"
"\n"
" println!(\"v: {:?}\", v.lock().unwrap());\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::sync::Mutex;\n"
"\n"
"fn main() {\n"
" let v = Mutex::new(vec![10, 20, 30]);\n"
" println!(\"v: {:?}\", v.lock().unwrap());\n"
"\n"
" {\n"
" let mut guard = v.lock().unwrap();\n"
" guard.push(40);\n"
" }\n"
"\n"
" println!(\"v: {:?}\", v.lock().unwrap());\n"
"}\n"
"```"
#: src/concurrency/shared_state/mutex.md:22
msgid ""
"Notice how we have a [`impl<T: Send> Sync for Mutex<T>`](https://doc.rust-"
"lang.org/std/sync/struct.Mutex.html#impl-Sync-for-Mutex%3CT%3E) blanket "
"implementation."
msgstr ""
"모든 `Mutex<T>`는 [`impl<T: Send> Sync for Mutex<T>`](https://doc.rust-lang."
"org/std/sync/struct.Mutex.html#impl-Sync-for-Mutex%3CT%3E)를 자동으로 구현함"
"을 참조하세요."
#: src/concurrency/shared_state/mutex.md:31
#, fuzzy
msgid ""
"`Mutex` in Rust looks like a collection with just one element - the "
"protected data."
msgstr ""
"러스트의 `Mutex`는 오직 하나의 데이터만 담을 수 있는 컬렉션처럼 볼 수도 있습"
"니다. 다른 컬렉션과 다른 점은, 그 데이터가 동시성 문제로부터 자유롭다는 점입"
"니다."
#: src/concurrency/shared_state/mutex.md:32
#, fuzzy
msgid ""
"It is not possible to forget to acquire the mutex before accessing the "
"protected data."
msgstr ""
"`Mutex`는 뮤텍스를 획득하지 않으면 보호된 데이터에 접근하는 것이 불가능 하도"
"록 디자인 되어 있습니다."
#: src/concurrency/shared_state/mutex.md:33
#, fuzzy
msgid ""
"You can get an `&mut T` from an `&Mutex<T>` by taking the lock. The "
"`MutexGuard` ensures that the `&mut T` doesn't outlive the lock being held."
msgstr ""
"`&Mutex<T>`에 대해 lock을 획득하면 `&mut T`를 얻을 수 있습니다. `MutexGuard`"
"는 `&mut T`가 획득한 lock보다 오래 살아남지 않음을 보장합니다."
#: src/concurrency/shared_state/mutex.md:35
#, fuzzy
msgid ""
"`Mutex<T>` implements both `Send` and `Sync` iff (if and only if) `T` "
"implements `Send`."
msgstr ""
"`Mutex<T>`는 오직 `T`가 `Send`를 구현하는 경우에만 `Send`와 `Sync`를 구현합니"
"다."
#: src/concurrency/shared_state/mutex.md:36
#, fuzzy
msgid "A read-write lock counterpart - `RwLock`."
msgstr "읽기-쓰기 lock은 `RwLock`을 사용합니다."
#: src/concurrency/shared_state/mutex.md:37
#, fuzzy
msgid "Why does `lock()` return a `Result`? "
msgstr "왜 `lock()`이 `Result`를 반환할까요?"
#: src/concurrency/shared_state/mutex.md:38
#, fuzzy
msgid ""
"If the thread that held the `Mutex` panicked, the `Mutex` becomes "
"\"poisoned\" to signal that the data it protected might be in an "
"inconsistent state. Calling `lock()` on a poisoned mutex fails with a "
"[`PoisonError`](https://doc.rust-lang.org/std/sync/struct.PoisonError.html). "
"You can call `into_inner()` on the error to recover the data regardless."
msgstr ""
"`Mutex`를 획득한 스레드에서 패닉이 발생하면, 데이터가 올바르지 않은 상황이 "
"될 수 있습니다. 이를 `Mutex`가 \"중독(poisoned)\" 되었다고 표현하며, 중독된 "
"뮤텍스에서 `lock()`을 호출하면 실패하고 [`PoisonError`](https://doc.rust-"
"lang.org/std/sync/struct.PoisonError.html)가 발생합니다. 이러한 오류로부터 데"
"이터를 복구하기 위해 `into_inner()`를 호출할 수 있습니다."
#: src/concurrency/shared_state/example.md:3
msgid "Let us see `Arc` and `Mutex` in action:"
msgstr "`Arc`와 `Mutex`의 동작을 살펴봅시다:"
#: src/concurrency/shared_state/example.md:5
#, fuzzy
msgid ""
"```rust,editable,compile_fail\n"
"use std::thread;\n"
"// use std::sync::{Arc, Mutex};\n"
"\n"
"fn main() {\n"
" let v = vec![10, 20, 30];\n"
" let handle = thread::spawn(|| {\n"
" v.push(10);\n"
" });\n"
" v.push(1000);\n"
"\n"
" handle.join().unwrap();\n"
" println!(\"v: {v:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::sync::{Arc, Mutex};\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let v = Arc::new(Mutex::new(vec![10, 20, 30]));\n"
"\n"
" let v2 = Arc::clone(&v);\n"
" let handle = thread::spawn(move || {\n"
" let mut v2 = v2.lock().unwrap();\n"
" v2.push(10);\n"
" });\n"
"\n"
" {\n"
" let mut v = v.lock().unwrap();\n"
" v.push(1000);\n"
" }\n"
"\n"
" handle.join().unwrap();\n"
"\n"
" println!(\"v: {v:?}\");\n"
"}\n"
"```"
#: src/concurrency/shared_state/example.md:23
msgid "Possible solution:"
msgstr "가능한 해결책:"
#: src/concurrency/shared_state/example.md:25
msgid ""
"```rust,editable\n"
"use std::sync::{Arc, Mutex};\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let v = Arc::new(Mutex::new(vec![10, 20, 30]));\n"
"\n"
" let v2 = Arc::clone(&v);\n"
" let handle = thread::spawn(move || {\n"
" let mut v2 = v2.lock().unwrap();\n"
" v2.push(10);\n"
" });\n"
"\n"
" {\n"
" let mut v = v.lock().unwrap();\n"
" v.push(1000);\n"
" }\n"
"\n"
" handle.join().unwrap();\n"
"\n"
" println!(\"v: {v:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable\n"
"use std::sync::{Arc, Mutex};\n"
"use std::thread;\n"
"\n"
"fn main() {\n"
" let v = Arc::new(Mutex::new(vec![10, 20, 30]));\n"
"\n"
" let v2 = Arc::clone(&v);\n"
" let handle = thread::spawn(move || {\n"
" let mut v2 = v2.lock().unwrap();\n"
" v2.push(10);\n"
" });\n"
"\n"
" {\n"
" let mut v = v.lock().unwrap();\n"
" v.push(1000);\n"
" }\n"
"\n"
" handle.join().unwrap();\n"
"\n"
" println!(\"v: {v:?}\");\n"
"}\n"
"```"
#: src/concurrency/shared_state/example.md:49
msgid "Notable parts:"
msgstr "눈여겨 볼 부분:"
#: src/concurrency/shared_state/example.md:51
msgid ""
"`v` is wrapped in both `Arc` and `Mutex`, because their concerns are "
"orthogonal."
msgstr ""
"`v`는 `Arc`와 `Mutex` 모두에 포함되어 있습니다. 이는 `Arc`와 `Mutex`가 서로 "
"완전히 다른 문제를 위한 도구이기 때문입니다."
#: src/concurrency/shared_state/example.md:52
msgid ""
"Wrapping a `Mutex` in an `Arc` is a common pattern to share mutable state "
"between threads."
msgstr ""
"`Mutex`를 `Arc`로 래핑하는 것은 가변 상태를 스레드들 간에 공유할 때 흔히 사용"
"하는 패턴입니다."
#: src/concurrency/shared_state/example.md:53
msgid ""
"`v: Arc<_>` needs to be cloned as `v2` before it can be moved into another "
"thread. Note `move` was added to the lambda signature."
msgstr ""
"`v: Arc<_>`를 다른 스레드에서 사용하려면, 먼저 `v2`로 복사를 하고 이를 그 스"
"레드로 이동 해야 합니다. 그래서 람다의 시그니처에 `move`가 있는 것입니다."
#: src/concurrency/shared_state/example.md:54
msgid ""
"Blocks are introduced to narrow the scope of the `LockGuard` as much as "
"possible."
msgstr "블록은 `LockGuard`의 범위를 최대한 좁히기 위해 사용되었습니다."
#: src/exercises/concurrency/morning.md:3
msgid "Let us practice our new concurrency skills with"
msgstr "동시성 기법들을 연습해 봅시다"
#: src/exercises/concurrency/morning.md:5
msgid "Dining philosophers: a classic problem in concurrency."
msgstr "식사하는 철학자 문제: 고적적인 동시성 문제입니다."
#: src/exercises/concurrency/morning.md:7
msgid ""
"Multi-threaded link checker: a larger project where you'll use Cargo to "
"download dependencies and then check links in parallel."
msgstr ""
"멀티 스레드 링크 검사기: 병렬적으로 웹페이지의 링크들을 체크합니다. 카고를 통"
"해 몇 가지 의존성들을 다운도르 받아야 하는 큰 프로젝트 입니다."
#: src/exercises/concurrency/dining-philosophers.md:3
msgid "The dining philosophers problem is a classic problem in concurrency:"
msgstr "식사하는 철학자 문제는 동시성에 있어서 고전적인 문제입니다:"
#: src/exercises/concurrency/dining-philosophers.md:5
msgid ""
"Five philosophers dine together at the same table. Each philosopher has "
"their own place at the table. There is a fork between each plate. The dish "
"served is a kind of spaghetti which has to be eaten with two forks. Each "
"philosopher can only alternately think and eat. Moreover, a philosopher can "
"only eat their spaghetti when they have both a left and right fork. Thus two "
"forks will only be available when their two nearest neighbors are thinking, "
"not eating. After an individual philosopher finishes eating, they will put "
"down both forks."
msgstr ""
"5명의 철학자가 원탁에서 식사를 하고 있습니다. 철학자는 원탁에서 자신의 자리"
"에 앉아있습니다. 포크는 각 접시 사이에 있습니다. 제공되는 요리를 먹기 위해서"
"는 두 개의 포크를 모두 사용해야합니다. 철학자는 생각을 하다가 배가 고프면 자"
"신의 좌,우의 포크를 들어 요리를 먹습니다. 철학자는 요리를 먹은 후에는 포크를 "
"다시 자리에 내려놓습니다. 철학자는 자신의 좌,우에 포크가 있을때만 요리를 먹"
"을 수 있습니다. 따라서 두 개의 포크는 오직 자신의 좌,우 철학자가 생각을 할 때"
"만 사용할 수 있습니다."
#: src/exercises/concurrency/dining-philosophers.md:13
#, fuzzy
msgid ""
"You will need a local [Cargo installation](../../cargo/running-locally.md) "
"for this exercise. Copy the code below to a file called `src/main.rs`, fill "
"out the blanks, and test that `cargo run` does not deadlock:"
msgstr ""
"이번 훈련에서는 [카고 설치하기](../../cargo/running-locally.md)가 필요합니"
"다. 아래 코드를 복사해서 `src/main.rs`에 붙여놓고 빈 부분을 채우고, `cargo "
"run` 커맨드로 테스트 해서 교착상태(데드락)가 발생하지 않는지 확인합니다:"
#: src/exercises/concurrency/dining-philosophers.md:19
msgid ""
"```rust,compile_fail\n"
"use std::sync::{mpsc, Arc, Mutex};\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"struct Fork;\n"
"\n"
"struct Philosopher {\n"
" name: String,\n"
" // left_fork: ...\n"
" // right_fork: ...\n"
" // thoughts: ...\n"
"}\n"
"\n"
"impl Philosopher {\n"
" fn think(&self) {\n"
" self.thoughts\n"
" .send(format!(\"Eureka! {} has a new idea!\", &self.name))\n"
" .unwrap();\n"
" }\n"
"\n"
" fn eat(&self) {\n"
" // Pick up forks...\n"
" println!(\"{} is eating...\", &self.name);\n"
" thread::sleep(Duration::from_millis(10));\n"
" }\n"
"}\n"
"\n"
"static PHILOSOPHERS: &[&str] =\n"
" &[\"Socrates\", \"Plato\", \"Aristotle\", \"Thales\", \"Pythagoras\"];\n"
"\n"
"fn main() {\n"
" // Create forks\n"
"\n"
" // Create philosophers\n"
"\n"
" // Make each of them think and eat 100 times\n"
"\n"
" // Output their thoughts\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/dining-philosophers.md:61
msgid "You can use the following `Cargo.toml`:"
msgstr ""
#: src/exercises/concurrency/dining-philosophers.md:65
msgid ""
"```toml\n"
"[package]\n"
"name = \"dining-philosophers\"\n"
"version = \"0.1.0\"\n"
"edition = \"2021\"\n"
"```"
msgstr ""
#: src/exercises/concurrency/link-checker.md:3
msgid ""
"Let us use our new knowledge to create a multi-threaded link checker. It "
"should start at a webpage and check that links on the page are valid. It "
"should recursively check other pages on the same domain and keep doing this "
"until all pages have been validated."
msgstr ""
"새로 배운것들을 활용해서 멀티 스레드 링크 검사기를 만듭니다. 이 검사기는 웹페"
"이지 안에 있는 링크들이 유효한지 확인합니다. 그리고 재귀적으로 동일 도메인의 "
"다른 모든 페이지가 유효한지 확인합니다."
#: src/exercises/concurrency/link-checker.md:8
msgid ""
"For this, you will need an HTTP client such as [`reqwest`](https://docs.rs/"
"reqwest/). Create a new Cargo project and `reqwest` it as a dependency with:"
msgstr ""
"이를 위해서 [`reqwest`](https://docs.rs/reqwest/)와 같은 HTTP 클라이언트가 필"
"요합니다. 새로운 로컬 프로젝트를 만들고 [`reqwest`](https://docs.rs/reqwest/)"
"를 의존성에 추가하십시요:"
#: src/exercises/concurrency/link-checker.md:11
#, fuzzy
msgid ""
"```shell\n"
"cargo new link-checker\n"
"cd link-checker\n"
"cargo add --features blocking,rustls-tls reqwest\n"
"```"
msgstr ""
"```shell\n"
"cargo init concurrency\n"
"cd concurrency\n"
"cargo add tokio --features full\n"
"cargo run\n"
"```"
#: src/exercises/concurrency/link-checker.md:17
msgid ""
"If `cargo add` fails with `error: no such subcommand`, then please edit the "
"`Cargo.toml` file by hand. Add the dependencies listed below."
msgstr ""
"만일 `cargo add` 커맨드가 `error: no such subcommand` 로 실패한다면 `Cargo."
"toml` 파일을 직접 수정해도 됩니다. 아래에 전체 의존성 내용이 있습니다."
#: src/exercises/concurrency/link-checker.md:20
msgid ""
"You will also need a way to find links. We can use [`scraper`](https://docs."
"rs/scraper/) for that:"
msgstr "링크를 찾기 위해서 [`scraper`](https://docs.rs/scraper/)도 추가합니다:"
#: src/exercises/concurrency/link-checker.md:22
#, fuzzy
msgid ""
"```shell\n"
"cargo add scraper\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin pac\n"
"```"
#: src/exercises/concurrency/link-checker.md:26
msgid ""
"Finally, we'll need some way of handling errors. We use [`thiserror`]"
"(https://docs.rs/thiserror/) for that:"
msgstr ""
"마지막으로 오류 처리하는 방법으로 [`thiserror`](https://docs.rs/thiserror/)"
"도 추가합니다:"
#: src/exercises/concurrency/link-checker.md:29
#, fuzzy
msgid ""
"```shell\n"
"cargo add thiserror\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin mmio\n"
"```"
#: src/exercises/concurrency/link-checker.md:33
msgid ""
"The `cargo add` calls will update the `Cargo.toml` file to look like this:"
msgstr "모든 `cargo add`가 끝나면 `Cargo.toml`에 아래 내용이 추가됩니다:"
#: src/exercises/concurrency/link-checker.md:37
msgid ""
"```toml\n"
"[package]\n"
"name = \"link-checker\"\n"
"version = \"0.1.0\"\n"
"edition = \"2021\"\n"
"publish = false\n"
"\n"
"[dependencies]\n"
"reqwest = { version = \"0.11.12\", features = [\"blocking\", \"rustls-"
"tls\"] }\n"
"scraper = \"0.13.0\"\n"
"thiserror = \"1.0.37\"\n"
"```"
msgstr ""
#: src/exercises/concurrency/link-checker.md:50
msgid ""
"You can now download the start page. Try with a small site such as `https://"
"www.google.org/`."
msgstr "이제 `https://www.google.org/` 같은 웹 페이지를 탐색할 수 있습니다."
#: src/exercises/concurrency/link-checker.md:53
msgid "Your `src/main.rs` file should look something like this:"
msgstr "`rc/main.rs`파일은 아래와 같습니다:"
#: src/exercises/concurrency/link-checker.md:57
msgid ""
"```rust,compile_fail\n"
"use reqwest::{blocking::Client, Url};\n"
"use scraper::{Html, Selector};\n"
"use thiserror::Error;\n"
"\n"
"#[derive(Error, Debug)]\n"
"enum Error {\n"
" #[error(\"request error: {0}\")]\n"
" ReqwestError(#[from] reqwest::Error),\n"
" #[error(\"bad http response: {0}\")]\n"
" BadResponse(String),\n"
"}\n"
"\n"
"#[derive(Debug)]\n"
"struct CrawlCommand {\n"
" url: Url,\n"
" extract_links: bool,\n"
"}\n"
"\n"
"fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, "
"Error> {\n"
" println!(\"Checking {:#}\", command.url);\n"
" let response = client.get(command.url.clone()).send()?;\n"
" if !response.status().is_success() {\n"
" return Err(Error::BadResponse(response.status().to_string()));\n"
" }\n"
"\n"
" let mut link_urls = Vec::new();\n"
" if !command.extract_links {\n"
" return Ok(link_urls);\n"
" }\n"
"\n"
" let base_url = response.url().to_owned();\n"
" let body_text = response.text()?;\n"
" let document = Html::parse_document(&body_text);\n"
"\n"
" let selector = Selector::parse(\"a\").unwrap();\n"
" let href_values = document\n"
" .select(&selector)\n"
" .filter_map(|element| element.value().attr(\"href\"));\n"
" for href in href_values {\n"
" match base_url.join(href) {\n"
" Ok(link_url) => {\n"
" link_urls.push(link_url);\n"
" }\n"
" Err(err) => {\n"
" println!(\"On {base_url:#}: ignored unparsable {href:?}: "
"{err}\");\n"
" }\n"
" }\n"
" }\n"
" Ok(link_urls)\n"
"}\n"
"\n"
"fn main() {\n"
" let client = Client::new();\n"
" let start_url = Url::parse(\"https://www.google.org\").unwrap();\n"
" let crawl_command = CrawlCommand{ url: start_url, extract_links: "
"true };\n"
" match visit_page(&client, &crawl_command) {\n"
" Ok(links) => println!(\"Links: {links:#?}\"),\n"
" Err(err) => println!(\"Could not extract links: {err:#}\"),\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/link-checker.md:120
msgid "Run the code in `src/main.rs` with"
msgstr "아래 커맨드로 소스를 실행합니다"
#: src/exercises/concurrency/link-checker.md:122
#, fuzzy
msgid ""
"```shell\n"
"cargo run\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin pac\n"
"```"
#: src/exercises/concurrency/link-checker.md:128
msgid ""
"Use threads to check the links in parallel: send the URLs to be checked to a "
"channel and let a few threads check the URLs in parallel."
msgstr ""
"스레드를 사용하여 링크를 병렬로 확인합니다: URL을 채널로 보내서 몇 개의 스레"
"드가 URL을 병렬로 체크하도록 합니다."
#: src/exercises/concurrency/link-checker.md:130
msgid ""
"Extend this to recursively extract links from all pages on the `www.google."
"org` domain. Put an upper limit of 100 pages or so so that you don't end up "
"being blocked by the site."
msgstr ""
"`www.google.org`도메인의 모든 페이지를 재귀적으로 확인하기 위해 코드를 확장해"
"서 작성합니다: 차단당하지 않도록 100페이지 정도로 제한을 두시기 바랍니다."
#: src/async.md:1
#, fuzzy
msgid "Async Rust"
msgstr "비동기"
#: src/async.md:3
msgid ""
"\"Async\" is a concurrency model where multiple tasks are executed "
"concurrently by executing each task until it would block, then switching to "
"another task that is ready to make progress. The model allows running a "
"larger number of tasks on a limited number of threads. This is because the "
"per-task overhead is typically very low and operating systems provide "
"primitives for efficiently identifying I/O that is able to proceed."
msgstr ""
"\"Async\"는 블럭될(더 이상 진행할 수 없을) 때까지 각 작업을 실행한 다음 진행"
"할 준비가 된 다른 작업으로 전환하여 여러 작업을 동시에 실행하는 동시 실행 모"
"델입니다. 이 모델을 사용하면 제한된 수의 스레드에서 더 많은 작업을 실행할 수 "
"있습니다. 이는, 한 작업을 유지하고 수행하는데 필요한 오버헤드가 (스레드에 비"
"해) 매우 낮고 운영체제가 여러 I/O들에서 현재 진행 가능한 I/O들을 효과적으로 "
"식별해 주는 프리미티브를 제공하기 때문입니다."
#: src/async.md:10
msgid ""
"Rust's asynchronous operation is based on \"futures\", which represent work "
"that may be completed in the future. Futures are \"polled\" until they "
"signal that they are complete."
msgstr ""
"Rust의 비동기 작업은 \"futures\"를 기반으로 하며 이는 미래에 완료될 수 있는 "
"작업을 나타냅니다. Futures는 완료되었다는 신호를 보낼 때까지 \"폴링\"됩니다."
#: src/async.md:14
msgid ""
"Futures are polled by an async runtime, and several different runtimes are "
"available."
msgstr ""
"Futures는 비동기 런타임에 의해 폴링되며, 비동기 런타임에는 여러 다양한 종류"
"가 있습니다."
#: src/async.md:17
#, fuzzy
msgid "Comparisons"
msgstr "비교"
#: src/async.md:19
msgid ""
"Python has a similar model in its `asyncio`. However, its `Future` type is "
"callback-based, and not polled. Async Python programs require a \"loop\", "
"similar to a runtime in Rust."
msgstr ""
"파이썬에도 `asyncio`라는 유사한 모델이 있습니다. 그러나 파이썬의 `Future` 타"
"입은 콜백 기반이며 폴링되지 않습니다. 파이썬으로 비동기 프로그래밍을 할 때에"
"는, Rust에서 런타임이 내부적으로 해 주는 것과 유사한, \"루프\"를 명시적으로 "
"사용해야 합니다."
#: src/async.md:23
msgid ""
"JavaScript's `Promise` is similar, but again callback-based. The language "
"runtime implements the event loop, so many of the details of Promise "
"resolution are hidden."
msgstr ""
"자바스크립트의 `Promise`도 비슷하지만 역시 콜백 기반입니다. 자바스크립트에서"
"는 이벤트 루프가런타임 엔진에서 구현되므로 `Promise`가 처리되는 세부 과정이 "
"숨겨집니다."
#: src/async/async-await.md:1
msgid "`async`/`await`"
msgstr "`async`/`await`"
#: src/async/async-await.md:3
msgid ""
"At a high level, async Rust code looks very much like \"normal\" sequential "
"code:"
msgstr ""
"겉에서 보았을 때, 비동기 Rust 코드는 일반적인 절차적 코드와 매우 유사합니다."
#: src/async/async-await.md:5
msgid ""
"```rust,editable,compile_fail\n"
"use futures::executor::block_on;\n"
"\n"
"async fn count_to(count: i32) {\n"
" for i in 1..=count {\n"
" println!(\"Count is: {i}!\");\n"
" }\n"
"}\n"
"\n"
"async fn async_main(count: i32) {\n"
" count_to(count).await;\n"
"}\n"
"\n"
"fn main() {\n"
" block_on(async_main(10));\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use futures::executor::block_on;\n"
"\n"
"async fn count_to(count: i32) {\n"
" for i in 1..=count {\n"
" println!(\"Count is: {i}!\");\n"
" }\n"
"}\n"
"\n"
"async fn async_main(count: i32) {\n"
" count_to(count).await;\n"
"}\n"
"\n"
"fn main() {\n"
" block_on(async_main(10));\n"
"}\n"
"```"
#: src/async/async-await.md:27
msgid ""
"Note that this is a simplified example to show the syntax. There is no long "
"running operation or any real concurrency in it!"
msgstr ""
"Rust 비동기 문법을 보여주는 간단한 예시입니다. 여기에는 오래 실행되는 작업이"
"나, 실제로 동시에 수행되는 것들은 없습니다."
#: src/async/async-await.md:30
msgid "What is the return type of an async call?"
msgstr "`async`함수의 리턴 타입은 무엇인가요?"
#: src/async/async-await.md:31
msgid "Use `let future: () = async_main(10);` in `main` to see the type."
msgstr ""
"`main`에서 \\`let future: () = async_main(10);을 사용하여 타입을 확인하세요."
#: src/async/async-await.md:33
msgid ""
"The \"async\" keyword is syntactic sugar. The compiler replaces the return "
"type with a future. "
msgstr ""
"\"async\" 키워드는 문법 설탕(syntactic sugar)입니다. 컴파일러가 리턴 타입을 "
"future로 바꿉니다. "
#: src/async/async-await.md:36
msgid ""
"You cannot make `main` async, without additional instructions to the "
"compiler on how to use the returned future."
msgstr ""
"`main`을 비동기 함수로 만들수는 없습니다. 만약 그렇게 할 경우 컴파일러는 리"
"턴 타입인 future를 어떻게 사용할 지 모르기 때문입니다."
#: src/async/async-await.md:39
msgid ""
"You need an executor to run async code. `block_on` blocks the current thread "
"until the provided future has run to completion. "
msgstr ""
"비동기 코드를 실행하려면 실행자(executor)가 필요합니다. `block_on` 실행자는 "
"제공된 future가 완료될 때까지 현재 스레드를 블록합니다. "
#: src/async/async-await.md:42
msgid ""
"`.await` asynchronously waits for the completion of another operation. "
"Unlike `block_on`, `.await` doesn't block the current thread."
msgstr ""
"`.await`는 다른 작업이 완료될 때까지 비동기적으로 대기합니다. `block_on`과 달"
"리 `.await`는 현재 스레드를 블록하지 않습니다."
#: src/async/async-await.md:45
msgid ""
"`.await` can only be used inside an `async` function (or block; these are "
"introduced later). "
msgstr ""
"`.await`는 `async` 함수(또는 나중에 소개될 `async` 블록) 안에서만 사용할 수 "
"있습니다. "
#: src/async/futures.md:3
msgid ""
"[`Future`](https://doc.rust-lang.org/std/future/trait.Future.html) is a "
"trait, implemented by objects that represent an operation that may not be "
"complete yet. A future can be polled, and `poll` returns a [`Poll`](https://"
"doc.rust-lang.org/std/task/enum.Poll.html)."
msgstr ""
"[`Future`](https://doc.rust-lang.org/std/future/trait.Future.html)는 트레잇입"
"니다.이 트레잇은 아직 완료되지 않았을 수도 있는 작업을 나타냅니다. Future는 "
"`poll` 함수를 통해 폴링될 수 있으며, 이 함수는 [`Poll`](https://doc.rust-"
"lang.org/std/task/enum.Poll.html)을 반환합니다."
#: src/async/futures.md:8
msgid ""
"```rust\n"
"use std::pin::Pin;\n"
"use std::task::Context;\n"
"\n"
"pub trait Future {\n"
" type Output;\n"
" fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::"
"Output>;\n"
"}\n"
"\n"
"pub enum Poll<T> {\n"
" Ready(T),\n"
" Pending,\n"
"}\n"
"```"
msgstr ""
"```rust\n"
"use std::pin::Pin;\n"
"use std::task::Context;\n"
"\n"
"pub trait Future {\n"
" type Output;\n"
" fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::"
"Output>;\n"
"}\n"
"\n"
"pub enum Poll<T> {\n"
" Ready(T),\n"
" Pending,\n"
"}\n"
"```"
#: src/async/futures.md:23
msgid ""
"An async function returns an `impl Future`. It's also possible (but "
"uncommon) to implement `Future` for your own types. For example, the "
"`JoinHandle` returned from `tokio::spawn` implements `Future` to allow "
"joining to it."
msgstr ""
"비동기 함수는 `impl Future`를 반환합니다. 새로운 타입을 만들고 이 타입이 "
"`Future`를 구현하게 할 수도 있지만 일반적이지는 않습니다. 예를 들어 `tokio::"
"spawn`가 리턴하는 `JoinHandle`은 `Future`를 구현하며, 이를 통해 생성된 스레드"
"에 join할 수 있습니다."
#: src/async/futures.md:27
msgid ""
"The `.await` keyword, applied to a Future, causes the current async function "
"to pause until that Future is ready, and then evaluates to its output."
msgstr ""
"Future에 `.await`를 호출하면, 해당 Future가 준비될 때까지 현재 비동기 함수가 "
"일시 중지됩니다. 그런 다음 Future가 준비가 되면, 그 값이 `.await` 구문의 값"
"이 됩니다."
#: src/async/futures.md:32
msgid ""
"The `Future` and `Poll` types are implemented exactly as shown; click the "
"links to show the implementations in the docs."
msgstr ""
"`Future` 와 `Poll` 타입의 실제 정의는 위에 보이는 그대로 입니다. 링크를 클릭"
"하면 Rust 문서에서 한 번 더 확인할 수 있습니다."
#: src/async/futures.md:35
msgid ""
"We will not get to `Pin` and `Context`, as we will focus on writing async "
"code, rather than building new async primitives. Briefly:"
msgstr ""
"본 강의의 목적은 비동기 코드를 작성하는데 있기 때문에, 새로운 비동기 프리미티"
"브를 만드는데 필요한 `Pin`과 `Context`는 다루지 않습니다. 이들에 대해 간단"
"히 설명하자면:"
#: src/async/futures.md:38
msgid ""
"`Context` allows a Future to schedule itself to be polled again when an "
"event occurs."
msgstr ""
"`Context`를 사용하면 Future가 이벤트가 발생할 때 다시 폴링되도록 예약할 수 있"
"습니다."
#: src/async/futures.md:41
msgid ""
"`Pin` ensures that the Future isn't moved in memory, so that pointers into "
"that future remain valid. This is required to allow references to remain "
"valid after an `.await`."
msgstr ""
"'Pin'을 사용하면 메모리에서 Future의 위치가 고정되기 때문에 해당 future의 포"
"인터가 항상 유효하게 유지됩니다. 이는 `.await` 후에 참조를 유효한 상태로 유지"
"하기 위해 필요합니다."
#: src/async/runtimes.md:3
msgid ""
"A _runtime_ provides support for performing operations asynchronously (a "
"_reactor_) and is responsible for executing futures (an _executor_). Rust "
"does not have a \"built-in\" runtime, but several options are available:"
msgstr ""
"비동기 _런타임_은 _리액터_ (비동기식 작업 실행을 지원)와 _실행자_ (futures를 "
"실행)의 두 가지 역할을 합니다. Rust 언어 자체에서 기본 제공하는 비동기 런타임"
"은 없습니다. 그러나 다음과 같은 비동기 런타임 크레잇들이 있습니다."
#: src/async/runtimes.md:7
#, fuzzy
msgid ""
"[Tokio](https://tokio.rs/): performant, with a well-developed ecosystem of "
"functionality like [Hyper](https://hyper.rs/) for HTTP or [Tonic](https://"
"github.com/hyperium/tonic) for gRPC."
msgstr ""
"[Tokio](https://tokio.rs/) - 성능이 우수합니다. 그리고 HTTP를 지원하는 "
"[Hyper](https://hyper.rs/) 와 gRPC를 지원하는 [Tonic](https://github.com/"
"hyperium/tonic)과 같은 잘 발달된 라이브러리 생태계가 있습니다."
#: src/async/runtimes.md:10
#, fuzzy
msgid ""
"[async-std](https://async.rs/): aims to be a \"std for async\", and includes "
"a basic runtime in `async::task`."
msgstr ""
"[async-std](https://async.rs/) - 비동기에서의 `std`를 목표로 하고 있습니다. "
"`async::task`에 기본 런타임이 포함되어 있습니다."
#: src/async/runtimes.md:12
#, fuzzy
msgid "[smol](https://docs.rs/smol/latest/smol/): simple and lightweight"
msgstr "[smol](https://docs.rs/smol/latest/smol/) - 간단하고 가볍습니다."
#: src/async/runtimes.md:14
msgid ""
"Several larger applications have their own runtimes. For example, [Fuchsia]"
"(https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/fuchsia-"
"async/src/lib.rs) already has one."
msgstr ""
"여러 대규모 애플리케이션에는 자체 런타임이 있는 경우도 있습니다. 예들 들어 "
"[Fuchsia](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/lib/"
"fuchsia-async/src/lib.rs)가 있습니다."
#: src/async/runtimes.md:20
msgid ""
"Note that of the listed runtimes, only Tokio is supported in the Rust "
"playground. The playground also does not permit any I/O, so most interesting "
"async things can't run in the playground."
msgstr ""
"Rust 플레이그라운드에서는 위에 나열된 비동기 런타임 중에서 Tokio만 사용할 수 "
"있습니다. 또한 Rust 플레이그라운드는 I/O를 허용하지 않으므로 async를 가지고 "
"할 수 있는 많은 흥미로운 작업들이 불가능 합니다."
#: src/async/runtimes.md:24
msgid ""
"Futures are \"inert\" in that they do not do anything (not even start an I/O "
"operation) unless there is an executor polling them. This differs from JS "
"Promises, for example, which will run to completion even if they are never "
"used."
msgstr ""
"Futures는 실행자가 폴링하지 않는 한 아무것도 하지 않는다는 점에서(I/O 작업조"
"차 시작하지 않음) \"비활성\" 상태입니다. 이는 사용되지 않는 경우에도 완료될 "
"때 까지 실행되는, 자바 스크립트의 promise와 다릅니다."
#: src/async/runtimes/tokio.md:4
msgid "Tokio provides: "
msgstr "Tokio는 다음을 제공합니다. "
#: src/async/runtimes/tokio.md:6
msgid "A multi-threaded runtime for executing asynchronous code."
msgstr "비동기 코드 실행을 위한 멀티스레드 런타임"
#: src/async/runtimes/tokio.md:7
msgid "An asynchronous version of the standard library."
msgstr "표준 라이브러리의 비동기 버전"
#: src/async/runtimes/tokio.md:8
msgid "A large ecosystem of libraries."
msgstr "대규모 라이브러리 생태계"
#: src/async/runtimes/tokio.md:10
msgid ""
"```rust,editable,compile_fail\n"
"use tokio::time;\n"
"\n"
"async fn count_to(count: i32) {\n"
" for i in 1..=count {\n"
" println!(\"Count in task: {i}!\");\n"
" time::sleep(time::Duration::from_millis(5)).await;\n"
" }\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" tokio::spawn(count_to(10));\n"
"\n"
" for i in 1..5 {\n"
" println!(\"Main task: {i}\");\n"
" time::sleep(time::Duration::from_millis(5)).await;\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use tokio::time;\n"
"\n"
"async fn count_to(count: i32) {\n"
" for i in 1..=count {\n"
" println!(\"Count in task: {i}!\");\n"
" time::sleep(time::Duration::from_millis(5)).await;\n"
" }\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" tokio::spawn(count_to(10));\n"
"\n"
" for i in 1..5 {\n"
" println!(\"Main task: {i}\");\n"
" time::sleep(time::Duration::from_millis(5)).await;\n"
" }\n"
"}\n"
"```"
#: src/async/runtimes/tokio.md:33
msgid "With the `tokio::main` macro we can now make `main` async."
msgstr ""
"이제 `tokio::main` 매크로를 사용하면 `main`을 비동기로 만들 수 있습니다."
#: src/async/runtimes/tokio.md:35
msgid "The `spawn` function creates a new, concurrent \"task\"."
msgstr "`spawn` 함수는 동시 실행되는 새로운 \"작업\"을 만듭니다."
#: src/async/runtimes/tokio.md:37
msgid "Note: `spawn` takes a `Future`, you don't call `.await` on `count_to`."
msgstr ""
"참고: `spawn`은 `Future`를 인자로 받습니다. 때문에 `count_to`에 `.await`를 호"
"출하지 않는 점을 주목하세요."
#: src/async/runtimes/tokio.md:39
msgid "**Further exploration:**"
msgstr "**심화 학습:**"
#: src/async/runtimes/tokio.md:41
msgid ""
"Why does `count_to` not (usually) get to 10? This is an example of async "
"cancellation. `tokio::spawn` returns a handle which can be awaited to wait "
"until it finishes."
msgstr ""
"`count_to`가 10에 도달하지 않는 경우가 많은데 그 이유는 무엇일까요? 이는 비동"
"기적인 취소를 보여주는 예입니다. `tokio::spawn`이 리턴하는 것은 완료될 때까"
"지 기다리도록 대기하는데 사용되는 핸들입니다."
#: src/async/runtimes/tokio.md:45
msgid "Try `count_to(10).await` instead of spawning."
msgstr "`tokio::spawn` 대신 `count_to(10).await`를 사용해 보세요."
#: src/async/runtimes/tokio.md:47
msgid "Try awaiting the task returned from `tokio::spawn`."
msgstr "`tokio::spawn`에서 반환된 작업을 `await` 해 보세요."
#: src/async/tasks.md:3
msgid "Rust has a task system, which is a form of lightweight threading."
msgstr "Rust의 태스크(작업) 시스템은 경량 스레딩의 한 종류로 볼 수 있습니다."
#: src/async/tasks.md:5
msgid ""
"A task has a single top-level future which the executor polls to make "
"progress. That future may have one or more nested futures that its `poll` "
"method polls, corresponding loosely to a call stack. Concurrency within a "
"task is possible by polling multiple child futures, such as racing a timer "
"and an I/O operation."
msgstr ""
"하나의 작업에는, 실행자가 이 작업을 진행하기 위해 계속 폴링하는, 최상위 "
"future가 한 개 있습니다. 이 future에는 `poll` 메서드가 폴링하는 중첩된 future"
"가 한 개 이상 있을 수 있습니다. 이러한 중첩된 future는 일반적인 함수 호출 스"
"택하고 비슷한 역할을 합니다. 한 작업 안에서 여러 자식 future들을 폴링하면, 타"
"이머를 켜는 것과 어떤 I/O작업을 동시에 수행시킨 후 타이머와 I/O 중 먼저 끝나"
"는 것을 기다리는 것과 같은동시성도 구현할 수 있습니다."
#: src/async/tasks.md:10
msgid ""
"```rust,compile_fail\n"
"use tokio::io::{self, AsyncReadExt, AsyncWriteExt};\n"
"use tokio::net::TcpListener;\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> io::Result<()> {\n"
" let listener = TcpListener::bind(\"127.0.0.1:6142\").await?;\n"
"\tprintln!(\"listening on port 6142\");\n"
"\n"
" loop {\n"
" let (mut socket, addr) = listener.accept().await?;\n"
"\n"
" println!(\"connection from {addr:?}\");\n"
"\n"
" tokio::spawn(async move {\n"
" if let Err(e) = socket.write_all(b\"Who are you?\\n\").await {\n"
" println!(\"socket error: {e:?}\");\n"
" return;\n"
" }\n"
"\n"
" let mut buf = vec![0; 1024];\n"
" let reply = match socket.read(&mut buf).await {\n"
" Ok(n) => {\n"
" let name = std::str::from_utf8(&buf[..n]).unwrap()."
"trim();\n"
" format!(\"Thanks for dialing in, {name}!\\n\")\n"
" }\n"
" Err(e) => {\n"
" println!(\"socket error: {e:?}\");\n"
" return;\n"
" }\n"
" };\n"
"\n"
" if let Err(e) = socket.write_all(reply.as_bytes()).await {\n"
" println!(\"socket error: {e:?}\");\n"
" }\n"
" });\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,compile_fail\n"
"use tokio::io::{self, AsyncReadExt, AsyncWriteExt};\n"
"use tokio::net::TcpListener;\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> io::Result<()> {\n"
" let listener = TcpListener::bind(\"127.0.0.1:6142\").await?;\n"
"\tprintln!(\"listening on port 6142\");\n"
"\n"
" loop {\n"
" let (mut socket, addr) = listener.accept().await?;\n"
"\n"
" println!(\"connection from {addr:?}\");\n"
"\n"
" tokio::spawn(async move {\n"
" if let Err(e) = socket.write_all(b\"Who are you?\\n\").await {\n"
" println!(\"socket error: {e:?}\");\n"
" return;\n"
" }\n"
"\n"
" let mut buf = vec![0; 1024];\n"
" let reply = match socket.read(&mut buf).await {\n"
" Ok(n) => {\n"
" let name = std::str::from_utf8(&buf[..n]).unwrap()."
"trim();\n"
" format!(\"Thanks for dialing in, {name}!\\n\")\n"
" }\n"
" Err(e) => {\n"
" println!(\"socket error: {e:?}\");\n"
" return;\n"
" }\n"
" };\n"
"\n"
" if let Err(e) = socket.write_all(reply.as_bytes()).await {\n"
" println!(\"socket error: {e:?}\");\n"
" }\n"
" });\n"
" }\n"
"}\n"
"```"
#: src/async/tasks.md:52 src/async/control-flow/join.md:36
msgid ""
"Copy this example into your prepared `src/main.rs` and run it from there."
msgstr ""
"이 예제를, 로컬 컴퓨터에 만들어 둔 `src/main.rs`에 복사하고 거기에서 실행하세"
"요."
#: src/async/tasks.md:54
msgid ""
"Ask students to visualize what the state of the example server would be with "
"a few connected clients. What tasks exist? What are their Futures?"
msgstr ""
"수강생들에게 이 서버에 몇 개의 클라이언트가 연결되면 이 서버의 상태가 어떻게 "
"변할지 그림을 그려보도록 하세요. 어떤 태스크들이 있는지, 이 태스크들의 Future"
"는 어떤 상태에 있는지 물어봅니다."
#: src/async/tasks.md:57
msgid ""
"This is the first time we've seen an `async` block. This is similar to a "
"closure, but does not take any arguments. Its return value is a Future, "
"similar to an `async fn`. "
msgstr ""
"`async` 블록을 처음 보게 되었습니다. 이것은 클로저와 비슷하지만 인자를 받지 "
"않습니다. 리턴 타입은 `async fn`과 비슷한 Future입니다. "
#: src/async/tasks.md:61
msgid ""
"Refactor the async block into a function, and improve the error handling "
"using `?`."
msgstr ""
"Async 블록을 함수로 리팩터링하고 `?`를 사용하여 오류 처리를 개선해 봅시다."
#: src/async/channels.md:3
msgid ""
"Several crates have support for asynchronous channels. For instance `tokio`:"
msgstr ""
"여러 크레이트에서 비동기 채널을 지원합니다. 예를 들어 `tokio`에서는 아래와 같"
"이합니다."
#: src/async/channels.md:5
#, fuzzy
msgid ""
"```rust,editable,compile_fail\n"
"use tokio::sync::mpsc::{self, Receiver};\n"
"\n"
"async fn ping_handler(mut input: Receiver<()>) {\n"
" let mut count: usize = 0;\n"
"\n"
" while let Some(_) = input.recv().await {\n"
" count += 1;\n"
" println!(\"Received {count} pings so far.\");\n"
" }\n"
"\n"
" println!(\"ping_handler complete\");\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let (sender, receiver) = mpsc::channel(32);\n"
" let ping_handler_task = tokio::spawn(ping_handler(receiver));\n"
" for i in 0..10 {\n"
" sender.send(()).await.expect(\"Failed to send ping.\");\n"
" println!(\"Sent {} pings so far.\", i + 1);\n"
" }\n"
"\n"
" drop(sender);\n"
" ping_handler_task.await.expect(\"Something went wrong in ping handler "
"task.\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use tokio::sync::mpsc::{self, Receiver};\n"
"\n"
"async fn ping_handler(mut input: Receiver<()>) {\n"
" let mut count: usize = 0;\n"
"\n"
" while let Some(_) = input.recv().await {\n"
" count += 1;\n"
" println!(\"Received {count} pings so far.\");\n"
" }\n"
"\n"
" println!(\"ping_handler complete\");\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let (sender, receiver) = mpsc::channel(32);\n"
" let ping_handler_task = tokio::spawn(ping_handler(receiver));\n"
" for i in 0..10 {\n"
" sender.send(()).await.expect(\"Failed to send ping.\");\n"
" println!(\"Sent {} pings so far.\", i + 1);\n"
" }\n"
"\n"
" std::mem::drop(sender);\n"
" ping_handler_task.await.expect(\"Something went wrong in ping handler "
"task.\");\n"
"}\n"
"```"
#: src/async/channels.md:35
msgid "Change the channel size to `3` and see how it affects the execution."
msgstr "채널 크기를 `3`으로 변경하고 동작이 어떻게 바뀌는지 확인하세요."
#: src/async/channels.md:37
msgid ""
"Overall, the interface is similar to the `sync` channels as seen in the "
"[morning class](concurrency/channels.md)."
msgstr ""
"비동기 채널을 사용하기 위한 인터페이스는 [오전 과정](concurrency/channels.md)"
"에서 배운 `sync` 채널과 비슷합니다."
#: src/async/channels.md:40
msgid "Try removing the `std::mem::drop` call. What happens? Why?"
msgstr ""
"`std::mem::drop` 호출하는 줄을 삭제해 보세요. 어떤 결과가 나타나나요? 이유가 "
"무엇인가요?"
#: src/async/channels.md:42
msgid ""
"The [Flume](https://docs.rs/flume/latest/flume/) crate has channels that "
"implement both `sync` and `async` `send` and `recv`. This can be convenient "
"for complex applications with both IO and heavy CPU processing tasks."
msgstr ""
"[Flume](https://docs.rs/flume/latest/flume/) 크레이트에는 `sync`와 `async`, "
"`send`와 `recv`를 모두 구현하는 채널이 있습니다. 이것은 IO와 CPU 처리 작업이 "
"많은 복잡한 애플리케이션을 구현할 때 매우 유용합니다."
#: src/async/channels.md:46
msgid ""
"What makes working with `async` channels preferable is the ability to "
"combine them with other `future`s to combine them and create complex control "
"flow."
msgstr ""
"`async` 채널을 사용하는 것이 더 좋은 이유는 이를 다른 `future`와 결합하여 복"
"잡한 제어 흐름을 만들 수 있기 때문입니다."
#: src/async/control-flow.md:1
#, fuzzy
msgid "Futures Control Flow"
msgstr "흐름 제어"
#: src/async/control-flow.md:3
msgid ""
"Futures can be combined together to produce concurrent compute flow graphs. "
"We have already seen tasks, that function as independent threads of "
"execution."
msgstr ""
"Future들을 결합하여 계산 과정을 동시성이 있는 플로우 그래프 형태로 모델링 할 "
"수 있습니다. 앞서 배운, 각 태스크가 독립적으로 수행되도록 하는 것도 Future들"
"을 결합하는 한 방법으로 볼 수 있습니다."
#: src/async/control-flow.md:6
msgid "[Join](control-flow/join.md)"
msgstr "[Join](control-flow/join.md)"
#: src/async/control-flow.md:7
msgid "[Select](control-flow/select.md)"
msgstr "[Select](control-flow/select.md)"
#: src/async/control-flow/join.md:3
msgid ""
"A join operation waits until all of a set of futures are ready, and returns "
"a collection of their results. This is similar to `Promise.all` in "
"JavaScript or `asyncio.gather` in Python."
msgstr ""
"Join 연산은 모든 future가 준비될 때까지 기다린 후, 각 future의 결과값을 담은 "
"컬렉션을 리턴합니다. 이는 자바스크립트의 `Promise.all`이나 파이썬의 `asyncio."
"gather`와 유사합니다."
#: src/async/control-flow/join.md:7
msgid ""
"```rust,editable,compile_fail\n"
"use anyhow::Result;\n"
"use futures::future;\n"
"use reqwest;\n"
"use std::collections::HashMap;\n"
"\n"
"async fn size_of_page(url: &str) -> Result<usize> {\n"
" let resp = reqwest::get(url).await?;\n"
" Ok(resp.text().await?.len())\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let urls: [&str; 4] = [\n"
" \"https://google.com\",\n"
" \"https://httpbin.org/ip\",\n"
" \"https://play.rust-lang.org/\",\n"
" \"BAD_URL\",\n"
" ];\n"
" let futures_iter = urls.into_iter().map(size_of_page);\n"
" let results = future::join_all(futures_iter).await;\n"
" let page_sizes_dict: HashMap<&str, Result<usize>> =\n"
" urls.into_iter().zip(results.into_iter()).collect();\n"
" println!(\"{:?}\", page_sizes_dict);\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use anyhow::Result;\n"
"use futures::future;\n"
"use reqwest;\n"
"use std::collections::HashMap;\n"
"\n"
"async fn size_of_page(url: &str) -> Result<usize> {\n"
" let resp = reqwest::get(url).await?;\n"
" Ok(resp.text().await?.len())\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let urls: [&str; 4] = [\n"
" \"https://google.com\",\n"
" \"https://httpbin.org/ip\",\n"
" \"https://play.rust-lang.org/\",\n"
" \"BAD_URL\",\n"
" ];\n"
" let futures_iter = urls.into_iter().map(size_of_page);\n"
" let results = future::join_all(futures_iter).await;\n"
" let page_sizes_dict: HashMap<&str, Result<usize>> =\n"
" urls.into_iter().zip(results.into_iter()).collect();\n"
" println!(\"{:?}\", page_sizes_dict);\n"
"}\n"
"```"
#: src/async/control-flow/join.md:38
msgid ""
"For multiple futures of disjoint types, you can use `std::future::join!` but "
"you must know how many futures you will have at compile time. This is "
"currently in the `futures` crate, soon to be stabilised in `std::future`."
msgstr ""
"서로 다른 타입을 가지는 여러 여러 futures들을 join하고자 할 경우 `std::"
"future::join!`을 사용할 수 있습니다. 이 매크로를 사용하려면 futures가 몇 개"
"나 있을지 컴파일 할 때 알아야 한다는 점을 주의하세요. 이 매크로는 지금은 "
"'futures' 크레이트에 있으며 곧 안정화 되어 `std::future`에 포함될 예정입니다."
#: src/async/control-flow/join.md:42
msgid ""
"The risk of `join` is that one of the futures may never resolve, this would "
"cause your program to stall. "
msgstr ""
"'join'의 위험성은 futures들 중 하나가 영영 끝나지 않을 수도 있다는 것입니다. "
"그러면 프로그램이 더이상 진행을 못하고 멈춰있을(stall) 수 있습니다. "
#: src/async/control-flow/join.md:45
msgid ""
"You can also combine `join_all` with `join!` for instance to join all "
"requests to an http service as well as a database query. Try adding a "
"`tokio::time::sleep` to the future, using `futures::join!`. This is not a "
"timeout (that requires `select!`, explained in the next chapter), but "
"demonstrates `join!`."
msgstr ""
"`join_all`을 `join!`과 결합하여 http 서비스와 데이터베이스에 대한 모든 요청들"
"을 한꺼번에 진행시킬 수도 있습니다. `futures::join!`을 사용하여 `tokio::"
"time::sleep`을 future에 추가해 보세요. 이건 타임아웃을 구현하는 것이 아님을 "
"주의하세요. 실제로, 타임아웃은 다음 장에서 설명하는 `select!`를 사용해서 구"
"현해야 합니다. 여기서는 `tokio::time::sleep`을 사용한 것은 단순히 `join!`의 "
"동작을 설명하기 위함입니다."
#: src/async/control-flow/select.md:3
msgid ""
"A select operation waits until any of a set of futures is ready, and "
"responds to that future's result. In JavaScript, this is similar to `Promise."
"race`. In Python, it compares to `asyncio.wait(task_set, return_when=asyncio."
"FIRST_COMPLETED)`."
msgstr ""
"Select 연산은 여러 future들 모두에 대해서 준비될 때 까지 기다리다가, 그 중 어"
"떤 한 future가 최초로 준비 상태가 되면 해당 future의 결과값을 리턴합니다. 이"
"것은 자바스크립트에서의 `Promise.race`와 비슷합니다. 파이썬에서라면 `asyncio."
"wait(task_set, return_when=asyncio.FIRST_COMPLETED)`가 하는 동작과 비슷합니"
"다."
#: src/async/control-flow/select.md:8
msgid ""
"Similar to a match statement, the body of `select!` has a number of arms, "
"each of the form `pattern = future => statement`. When the `future` is "
"ready, the `statement` is executed with the variables in `pattern` bound to "
"the `future`'s result."
msgstr ""
"`select!` 안에는, `match`문과 비슷하게, `pattern = future => statement` 형태"
"의 브랜치(arm) 들이 있습니다. 어떤 'future'가 진행 가능 상태가 되면 '그 "
"`future`의 결과값이 `pattern`으로 바인딩 되며, 그 상태에서 \\`statement'가 수"
"행됩니다."
#: src/async/control-flow/select.md:13
msgid ""
"```rust,editable,compile_fail\n"
"use tokio::sync::mpsc::{self, Receiver};\n"
"use tokio::time::{sleep, Duration};\n"
"\n"
"#[derive(Debug, PartialEq)]\n"
"enum Animal {\n"
" Cat { name: String },\n"
" Dog { name: String },\n"
"}\n"
"\n"
"async fn first_animal_to_finish_race(\n"
" mut cat_rcv: Receiver<String>,\n"
" mut dog_rcv: Receiver<String>,\n"
") -> Option<Animal> {\n"
" tokio::select! {\n"
" cat_name = cat_rcv.recv() => Some(Animal::Cat { name: cat_name? }),\n"
" dog_name = dog_rcv.recv() => Some(Animal::Dog { name: dog_name? })\n"
" }\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let (cat_sender, cat_receiver) = mpsc::channel(32);\n"
" let (dog_sender, dog_receiver) = mpsc::channel(32);\n"
" tokio::spawn(async move {\n"
" sleep(Duration::from_millis(500)).await;\n"
" cat_sender\n"
" .send(String::from(\"Felix\"))\n"
" .await\n"
" .expect(\"Failed to send cat.\");\n"
" });\n"
" tokio::spawn(async move {\n"
" sleep(Duration::from_millis(50)).await;\n"
" dog_sender\n"
" .send(String::from(\"Rex\"))\n"
" .await\n"
" .expect(\"Failed to send dog.\");\n"
" });\n"
"\n"
" let winner = first_animal_to_finish_race(cat_receiver, dog_receiver)\n"
" .await\n"
" .expect(\"Failed to receive winner\");\n"
"\n"
" println!(\"Winner is {winner:?}\");\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use tokio::sync::mpsc::{self, Receiver};\n"
"use tokio::time::{sleep, Duration};\n"
"\n"
"#[derive(Debug, PartialEq)]\n"
"enum Animal {\n"
" Cat { name: String },\n"
" Dog { name: String },\n"
"}\n"
"\n"
"async fn first_animal_to_finish_race(\n"
" mut cat_rcv: Receiver<String>,\n"
" mut dog_rcv: Receiver<String>,\n"
") -> Option<Animal> {\n"
" tokio::select! {\n"
" cat_name = cat_rcv.recv() => Some(Animal::Cat { name: cat_name? }),\n"
" dog_name = dog_rcv.recv() => Some(Animal::Dog { name: dog_name? })\n"
" }\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let (cat_sender, cat_receiver) = mpsc::channel(32);\n"
" let (dog_sender, dog_receiver) = mpsc::channel(32);\n"
" tokio::spawn(async move {\n"
" sleep(Duration::from_millis(500)).await;\n"
" cat_sender\n"
" .send(String::from(\"Felix\"))\n"
" .await\n"
" .expect(\"Failed to send cat.\");\n"
" });\n"
" tokio::spawn(async move {\n"
" sleep(Duration::from_millis(50)).await;\n"
" dog_sender\n"
" .send(String::from(\"Rex\"))\n"
" .await\n"
" .expect(\"Failed to send dog.\");\n"
" });\n"
"\n"
" let winner = first_animal_to_finish_race(cat_receiver, dog_receiver)\n"
" .await\n"
" .expect(\"Failed to receive winner\");\n"
"\n"
" println!(\"Winner is {winner:?}\");\n"
"}\n"
"```"
#: src/async/control-flow/select.md:62
#, fuzzy
msgid ""
"In this example, we have a race between a cat and a dog. "
"`first_animal_to_finish_race` listens to both channels and will pick "
"whichever arrives first. Since the dog takes 50ms, it wins against the cat "
"that take 500ms seconds."
msgstr ""
"이 예제에서는 고양이와 개를 경주시켰습니다(동시에 시작시킨 후, 둘 중 먼저 끝"
"나는 쪽이 이김). `first_animal_to_finish_race`함수는 두 채널 모두에 귀기울이"
"고(listen하고) 있다가, 메시지가 먼저 도착한 채널을 선택합니다. 개는 50ms만에 "
"작업을 끝내고 고양이는 500ms가 걸리기 때문에, 개가 이깁니다."
#: src/async/control-flow/select.md:67
#, fuzzy
msgid ""
"You can use `oneshot` channels in this example as the channels are supposed "
"to receive only one `send`."
msgstr ""
"이 예제에서는 `oneshot` 채널을 사용하는 것이 더 좋은 디자인 입니다. 각 채널"
"이 한 번의 `send`만 수신해야 하는 것이 보장되기 때문입니다."
#: src/async/control-flow/select.md:70
#, fuzzy
msgid ""
"Try adding a deadline to the race, demonstrating selecting different sorts "
"of futures."
msgstr ""
"이 경주에 타임아웃을 추가해서, 서로 다른 종류의 futures들을 동시에 `select`"
"할 수 있음을 확인해 보세요."
#: src/async/control-flow/select.md:73
#, fuzzy
msgid ""
"Note that `select!` drops unmatched branches, which cancels their futures. "
"It is easiest to use when every execution of `select!` creates new futures."
msgstr ""
"`select!`는 매칭되지 않은 다른 모든 브랜치에 대해 drop을 수행합니다. 따라서 "
"경쟁에서 진 모든 future들은 취소(cancel) 됩니다. `select!`를 실행할 때마다 "
"새로운 futures가 만들어지는 경우라면, 이러한 점이 매우 편하게 느껴질 것입니"
"다. Future가 취소되는 것을 막기 위해 future를 직접 전달하는 대신 `&mut "
"future`를 전달하는 것도 가능합니다. 하지만 이렇게 하면 문제가 발생할 수 있습"
"니다 (왜 그런지는 `Pin`설명할 때 자세히 설명하겠습니다)."
#: src/async/control-flow/select.md:76
msgid ""
"An alternative is to pass `&mut future` instead of the future itself, but "
"this can lead to issues, further discussed in the pinning slide."
msgstr ""
#: src/async/pitfalls.md:1
msgid "Pitfalls of async/await"
msgstr "async/await에서 주의해야할 함정"
#: src/async/pitfalls.md:3
msgid ""
"Async / await provides convenient and efficient abstraction for concurrent "
"asynchronous programming. However, the async/await model in Rust also comes "
"with its share of pitfalls and footguns. We illustrate some of them in this "
"chapter:"
msgstr ""
"Async와 await는 동시 비동기 프로그래밍을 위한 편리하고 효율적인 추상화를 제공"
"합니다. 하지만 Rust의 async/await 모델에도 문제는 있습니다. 이 장에서 몇 가"
"지 예를 살펴보겠습니다."
#: src/async/pitfalls.md:5
#, fuzzy
msgid "[Blocking the Executor](pitfalls/blocking-executor.md)"
msgstr "[실행자 차단](pitfalls/blocking-executor.md)"
#: src/async/pitfalls.md:6
#, fuzzy
msgid "[Pin](pitfalls/pin.md)"
msgstr "[고정](pitfalls/pin.md)"
#: src/async/pitfalls.md:7
#, fuzzy
msgid "[Async Traits](pitfalls/async-traits.md)"
msgstr "[비동기 트레잇](pitfall/async-traits.md)"
#: src/async/pitfalls.md:8
msgid "[Cancellation](pitfalls/cancellation.md)"
msgstr ""
#: src/async/pitfalls/blocking-executor.md:1
msgid "Blocking the executor"
msgstr "실행자(executor)를 블록시킴"
#: src/async/pitfalls/blocking-executor.md:3
msgid ""
"Most async runtimes only allow IO tasks to run concurrently. This means that "
"CPU blocking tasks will block the executor and prevent other tasks from "
"being executed. An easy workaround is to use async equivalent methods where "
"possible."
msgstr ""
"대부분의 비동기 런타임은 IO 작업만 동시에 실행되도록 허용합니다. 즉, CPU를 블"
"럭하는 태스크가 있는 경우, 이는 실행자(executor)를 블럭하게 되며, 그 결과로 "
"다른 태스크가 실행되지 않습니다. 이 문제를 해결하는 간단한 방법은, 항상 async"
"를 지원하는 메서드를 사용하는 것입니다."
#: src/async/pitfalls/blocking-executor.md:7
msgid ""
"```rust,editable,compile_fail\n"
"use futures::future::join_all;\n"
"use std::time::Instant;\n"
"\n"
"async fn sleep_ms(start: &Instant, id: u64, duration_ms: u64) {\n"
" std::thread::sleep(std::time::Duration::from_millis(duration_ms));\n"
" println!(\n"
" \"future {id} slept for {duration_ms}ms, finished after {}ms\",\n"
" start.elapsed().as_millis()\n"
" );\n"
"}\n"
"\n"
"#[tokio::main(flavor = \"current_thread\")]\n"
"async fn main() {\n"
" let start = Instant::now();\n"
" let sleep_futures = (1..=10).map(|t| sleep_ms(&start, t, t * 10));\n"
" join_all(sleep_futures).await;\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use futures::future::join_all;\n"
"use std::time::Instant;\n"
"\n"
"async fn sleep_ms(start: &Instant, id: u64, duration_ms: u64) {\n"
" std::thread::sleep(std::time::Duration::from_millis(duration_ms));\n"
" println!(\n"
" \"future {id} slept for {duration_ms}ms, finished after {}ms\",\n"
" start.elapsed().as_millis()\n"
" );\n"
"}\n"
"\n"
"#[tokio::main(flavor = \"current_thread\")]\n"
"async fn main() {\n"
" let start = Instant::now();\n"
" let sleep_futures = (1..=10).map(|t| sleep_ms(&start, t, t * 10));\n"
" join_all(sleep_futures).await;\n"
"}\n"
"```"
#: src/async/pitfalls/blocking-executor.md:29
msgid ""
"Run the code and see that the sleeps happen consecutively rather than "
"concurrently."
msgstr ""
"코드를 실행하여 sleep들이 동시에 진행되지 않고 순차적으로으로 진행되는지 확인"
"하세요."
#: src/async/pitfalls/blocking-executor.md:32
msgid ""
"The `\"current_thread\"` flavor puts all tasks on a single thread. This "
"makes the effect more obvious, but the bug is still present in the multi-"
"threaded flavor."
msgstr ""
"`flavor`를 `\"current_thread\"` 로 설정하면 모든 태스크가 하나의 스레드에서 "
"수행됩니다. 이렇게 하면 문제 상황이 더 분명히 드러납니다. 그러나 이 버그는 멀"
"티스레드인 경우에도 여전히 존재합니다."
#: src/async/pitfalls/blocking-executor.md:36
msgid ""
"Switch the `std::thread::sleep` to `tokio::time::sleep` and await its result."
msgstr ""
"`std::thread::sleep`을 `tokio::time::sleep`으로 바꾸고 그 결과를 `await`해 보"
"세요."
#: src/async/pitfalls/blocking-executor.md:38
msgid ""
"Another fix would be to `tokio::task::spawn_blocking` which spawns an actual "
"thread and transforms its handle into a future without blocking the executor."
msgstr ""
"또 다른 해결 방법은 `tokio::task::spawn_blocking`입니다. 이는 실제 스레드를 "
"생성하고, 그 스레드에 대한 핸들을 future로 변환함으로써 실행자가 블록되는 것"
"을 막습니다."
#: src/async/pitfalls/blocking-executor.md:41
msgid ""
"You should not think of tasks as OS threads. They do not map 1 to 1 and most "
"executors will allow many tasks to run on a single OS thread. This is "
"particularly problematic when interacting with other libraries via FFI, "
"where that library might depend on thread-local storage or map to specific "
"OS threads (e.g., CUDA). Prefer `tokio::task::spawn_blocking` in such "
"situations."
msgstr ""
"태스크를 OS 스레드라고 생각하면 안 됩니다. 태스크와 OS스레드는 일대일 매핑 관"
"계에 있지 않습니다. 대부분의 실행자는 하나의 OS 스레드에서 최대한 많은 태스크"
"를 수행하도록 설계되어 있습니다. 이점은 FFI를 통해 다른 라이브러리와 상호작용"
"할 때 특히 문제가 됩니다. 예를 들어, 해당 라이브러리가 스레드 로컬 저장소를 "
"이용하거나 특정 OS 스레드에 매핑될 수 있습니다(예: CUDA). 이러한 상황에서는 "
"`tokio::task::spawn_blocking`을 사용하는 것이 좋습니다."
#: src/async/pitfalls/blocking-executor.md:47
msgid ""
"Use sync mutexes with care. Holding a mutex over an `.await` may cause "
"another task to block, and that task may be running on the same thread."
msgstr ""
"동기화 뮤텍스를 주의해서 사용하세요. `.await` 위에 뮤텍스를 적용하면 다른 작"
"업이 차단될 수 있으며 해당 작업은 동일한 스레드에서 실행 중일 수 있습니다."
#: src/async/pitfalls/pin.md:3
msgid ""
"When you await a future, all local variables (that would ordinarily be "
"stored on a stack frame) are instead stored in the Future for the current "
"async block. If your future has pointers to data on the stack, those "
"pointers might get invalidated. This is unsafe."
msgstr ""
"Future에 대해 `await`를 호출하여 그 future가 준비되기를 기다릴 때, 모든 로컬 "
"변수(일반적으로 스택 프레임에 저장됨)는 그 future객체 안에 저장됩니다. 만약 "
"그 future에 스택에 있는 어떤 데이터로의 포인터가 있으면 이러한 포인터는 올바"
"르지 않을 수 있습니다. 안전하지 않습니다."
#: src/async/pitfalls/pin.md:8
msgid ""
"Therefore, you must guarantee that the addresses your future points to don't "
"change. That is why we need to `pin` futures. Using the same future "
"repeatedly in a `select!` often leads to issues with pinned values."
msgstr ""
"따라서 future가 가리키는 주소가 변경되지 않도록 해야 합니다. 이것이 future를 "
"`pin`(고정)해야 하는 이유입니다. `select!`에서 동일한 future를 반복적으로 사"
"용하면 고정 값 문제가 발생하는 경우가 많습니다."
#: src/async/pitfalls/pin.md:12
msgid ""
"```rust,editable,compile_fail\n"
"use tokio::sync::{mpsc, oneshot};\n"
"use tokio::task::spawn;\n"
"use tokio::time::{sleep, Duration};\n"
"\n"
"// A work item. In this case, just sleep for the given time and respond\n"
"// with a message on the `respond_on` channel.\n"
"#[derive(Debug)]\n"
"struct Work {\n"
" input: u32,\n"
" respond_on: oneshot::Sender<u32>,\n"
"}\n"
"\n"
"// A worker which listens for work on a queue and performs it.\n"
"async fn worker(mut work_queue: mpsc::Receiver<Work>) {\n"
" let mut iterations = 0;\n"
" loop {\n"
" tokio::select! {\n"
" Some(work) = work_queue.recv() => {\n"
" sleep(Duration::from_millis(10)).await; // Pretend to work.\n"
" work.respond_on\n"
" .send(work.input * 1000)\n"
" .expect(\"failed to send response\");\n"
" iterations += 1;\n"
" }\n"
" // TODO: report number of iterations every 100ms\n"
" }\n"
" }\n"
"}\n"
"\n"
"// A requester which requests work and waits for it to complete.\n"
"async fn do_work(work_queue: &mpsc::Sender<Work>, input: u32) -> u32 {\n"
" let (tx, rx) = oneshot::channel();\n"
" work_queue\n"
" .send(Work {\n"
" input,\n"
" respond_on: tx,\n"
" })\n"
" .await\n"
" .expect(\"failed to send on work queue\");\n"
" rx.await.expect(\"failed waiting for response\")\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let (tx, rx) = mpsc::channel(10);\n"
" spawn(worker(rx));\n"
" for i in 0..100 {\n"
" let resp = do_work(&tx, i).await;\n"
" println!(\"work result for iteration {i}: {resp}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use tokio::sync::{mpsc, oneshot};\n"
"use tokio::task::spawn;\n"
"use tokio::time::{sleep, Duration};\n"
"\n"
"// 작업 항목. 이 경우 지정된 시간 동안 절전 모드로 있다가\n"
"// `respond_on` 채널의 메시지로 응답합니다.\n"
"#[derive(Debug)]\n"
"struct Work {\n"
" input: u32,\n"
" respond_on: oneshot::Sender<u32>,\n"
"}\n"
"\n"
"// 대기열에서 작업을 리슨하고 실행하는 worker입니다.\n"
"async fn worker(mut work_queue: mpsc::Receiver<Work>) {\n"
" let mut iterations = 0;\n"
" loop {\n"
" tokio::select! {\n"
" Some(work) = work_queue.recv() => {\n"
" sleep(Duration::from_millis(10)).await; // Pretend to work.\n"
" work.respond_on\n"
" .send(work.input * 1000)\n"
" .expect(\"failed to send response\");\n"
" iterations += 1;\n"
" }\n"
" // TODO: 100ms마다 반복 횟수를 보고합니다.\n"
" }\n"
" }\n"
"}\n"
"\n"
"// 작업을 요청하고 작업이 완료될 때까지 기다리는 요청자입니다.\n"
"async fn do_work(work_queue: &mpsc::Sender<Work>, input: u32) -> u32 {\n"
" let (tx, rx) = oneshot::channel();\n"
" work_queue\n"
" .send(Work {\n"
" input,\n"
" respond_on: tx,\n"
" })\n"
" .await\n"
" .expect(\"failed to send on work queue\");\n"
" rx.await.expect(\"failed waiting for response\")\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let (tx, rx) = mpsc::channel(10);\n"
" spawn(worker(rx));\n"
" for i in 0..100 {\n"
" let resp = do_work(&tx, i).await;\n"
" println!(\"work result for iteration {i}: {resp}\");\n"
" }\n"
"}\n"
"```"
#: src/async/pitfalls/pin.md:68
msgid ""
"You may recognize this as an example of the actor pattern. Actors typically "
"call `select!` in a loop."
msgstr ""
"위에서 소개한 것은 액터(actor) 패턴의 한 예라고 봐도 무방합니다. 액터는 일반"
"적으로 루프 안에서 `select!`를 호출합니다."
#: src/async/pitfalls/pin.md:71
msgid ""
"This serves as a summation of a few of the previous lessons, so take your "
"time with it."
msgstr "이전 강의 몇 개의 내용을 요약한 것이기 때문에 천천히 살펴보세요."
#: src/async/pitfalls/pin.md:74
msgid ""
"Naively add a `_ = sleep(Duration::from_millis(100)) => { println!(..) }` to "
"the `select!`. This will never execute. Why?"
msgstr ""
"`_ = sleep(Duration::from_millis(100)) => { println!(..) }`을 `select!`에 추"
"가해 보세요. 이 작업은 실행되지 않습니다. 왜 그럴까요?"
#: src/async/pitfalls/pin.md:77
msgid ""
"Instead, add a `timeout_fut` containing that future outside of the `loop`:"
msgstr ""
"대신, 해당 future가 포함된 `timeout_fut`를 `loop` 외부에 추가해 보세요."
#: src/async/pitfalls/pin.md:79
msgid ""
"```rust,compile_fail\n"
"let mut timeout_fut = sleep(Duration::from_millis(100));\n"
"loop {\n"
" select! {\n"
" ..,\n"
" _ = timeout_fut => { println!(..); },\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,compile_fail\n"
"let mut timeout_fut = sleep(Duration::from_millis(100));\n"
"loop {\n"
" select! {\n"
" ..,\n"
" _ = timeout_fut => { println!(..); },\n"
" }\n"
"}\n"
"```"
#: src/async/pitfalls/pin.md:88
msgid ""
"This still doesn't work. Follow the compiler errors, adding `&mut` to the "
"`timeout_fut` in the `select!` to work around the move, then using `Box::"
"pin`:"
msgstr ""
"여전히 작동하지 않습니다. 컴파일러 오류를 따라 `select!`의 `timeout_fut`에 "
"`&mut`를 추가하여 Move 시멘틱 관련한 문제를 해결하고 `Box::pin`을 사용하세요."
#: src/async/pitfalls/pin.md:92
msgid ""
"```rust,compile_fail\n"
"let mut timeout_fut = Box::pin(sleep(Duration::from_millis(100)));\n"
"loop {\n"
" select! {\n"
" ..,\n"
" _ = &mut timeout_fut => { println!(..); },\n"
" }\n"
"}\n"
"```"
msgstr ""
"```rust,compile_fail\n"
"let mut timeout_fut = Box::pin(sleep(Duration::from_millis(100)));\n"
"loop {\n"
" select! {\n"
" ..,\n"
" _ = &mut timeout_fut => { println!(..); },\n"
" }\n"
"}\n"
"```"
#: src/async/pitfalls/pin.md:102
msgid ""
"This compiles, but once the timeout expires it is `Poll::Ready` on every "
"iteration (a fused future would help with this). Update to reset "
"`timeout_fut` every time it expires."
msgstr ""
"이는 컴파일은 되지만 타임 아웃이 되면 매번 반복할 때 마다 `Poll::Ready`가 됩"
"니다(융합된 future가 도움이 될 수 있음). 타임 아웃 될 때마다 `timeout_fut`를 "
"리셋하도록 수정하세요."
#: src/async/pitfalls/pin.md:106
msgid ""
"Box allocates on the heap. In some cases, `std::pin::pin!` (only recently "
"stabilized, with older code often using `tokio::pin!`) is also an option, "
"but that is difficult to use for a future that is reassigned."
msgstr ""
"Box는 힙에 할당합니다. 경우에 따라 `std::pin::pin!`(최근에야 안정화되었으며 "
"이전 코드는 `tokio::pin!`을 사용하는 경우가 많음)도 사용할 수 있지만 이는 재"
"할당된 future에 사용하기가 어렵습니다."
#: src/async/pitfalls/pin.md:110
msgid ""
"Another alternative is to not use `pin` at all but spawn another task that "
"will send to a `oneshot` channel every 100ms."
msgstr ""
"또 다른 방법은 `pin`을 아예 사용하지 않고 100ms마다 `oneshot` 채널에 전송할 "
"다른 작업을 생성하는 것입니다."
#: src/async/pitfalls/async-traits.md:3
msgid ""
"Async methods in traits are not yet supported in the stable channel ([An "
"experimental feature exists in nightly and should be stabilized in the mid "
"term.](https://blog.rust-lang.org/inside-rust/2022/11/17/async-fn-in-trait-"
"nightly.html))"
msgstr ""
"트레잇에 async 메소드를 추가하는 것은 아직 안정화 버전 채널에서 지원되지 않습"
"니다([실험용 기능은 nightly에 존재하며 조만간 안정화 될 것입니다](https://"
"blog.rust-lang.org/inside-rust/2022/11/17/async-fn-in-trait-nightly.html))."
#: src/async/pitfalls/async-traits.md:5
msgid ""
"The crate [async_trait](https://docs.rs/async-trait/latest/async_trait/) "
"provides a workaround through a macro:"
msgstr ""
"크레이트 [async_trait](https://docs.rs/async-trait/latest/async_trait/)은 매"
"크로를 통한 해결 방법을 제공합니다."
#: src/async/pitfalls/async-traits.md:7
msgid ""
"```rust,editable,compile_fail\n"
"use async_trait::async_trait;\n"
"use std::time::Instant;\n"
"use tokio::time::{sleep, Duration};\n"
"\n"
"#[async_trait]\n"
"trait Sleeper {\n"
" async fn sleep(&self);\n"
"}\n"
"\n"
"struct FixedSleeper {\n"
" sleep_ms: u64,\n"
"}\n"
"\n"
"#[async_trait]\n"
"impl Sleeper for FixedSleeper {\n"
" async fn sleep(&self) {\n"
" sleep(Duration::from_millis(self.sleep_ms)).await;\n"
" }\n"
"}\n"
"\n"
"async fn run_all_sleepers_multiple_times(sleepers: Vec<Box<dyn Sleeper>>, "
"n_times: usize) {\n"
" for _ in 0..n_times {\n"
" println!(\"running all sleepers..\");\n"
" for sleeper in &sleepers {\n"
" let start = Instant::now();\n"
" sleeper.sleep().await;\n"
" println!(\"slept for {}ms\", start.elapsed().as_millis());\n"
" }\n"
" }\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let sleepers: Vec<Box<dyn Sleeper>> = vec![\n"
" Box::new(FixedSleeper { sleep_ms: 50 }),\n"
" Box::new(FixedSleeper { sleep_ms: 100 }),\n"
" ];\n"
" run_all_sleepers_multiple_times(sleepers, 5).await;\n"
"}\n"
"```"
msgstr ""
"```rust,editable,compile_fail\n"
"use async_trait::async_trait;\n"
"use std::time::Instant;\n"
"use tokio::time::{sleep, Duration};\n"
"\n"
"#[async_trait]\n"
"trait Sleeper {\n"
" async fn sleep(&self);\n"
"}\n"
"\n"
"struct FixedSleeper {\n"
" sleep_ms: u64,\n"
"}\n"
"\n"
"#[async_trait]\n"
"impl Sleeper for FixedSleeper {\n"
" async fn sleep(&self) {\n"
" sleep(Duration::from_millis(self.sleep_ms)).await;\n"
" }\n"
"}\n"
"\n"
"async fn run_all_sleepers_multiple_times(sleepers: Vec<Box<dyn Sleeper>>, "
"n_times: usize) {\n"
" for _ in 0..n_times {\n"
" println!(\"running all sleepers..\");\n"
" for sleeper in &sleepers {\n"
" let start = Instant::now();\n"
" sleeper.sleep().await;\n"
" println!(\"slept for {}ms\", start.elapsed().as_millis());\n"
" }\n"
" }\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" let sleepers: Vec<Box<dyn Sleeper>> = vec![\n"
" Box::new(FixedSleeper { sleep_ms: 50 }),\n"
" Box::new(FixedSleeper { sleep_ms: 100 }),\n"
" ];\n"
" run_all_sleepers_multiple_times(sleepers, 5).await;\n"
"}\n"
"```"
#: src/async/pitfalls/async-traits.md:51
msgid ""
"`async_trait` is easy to use, but note that it's using heap allocations to "
"achieve this. This heap allocation has performance overhead."
msgstr ""
"`async_trait`은 사용하기 쉽지만 이를 위해 힙에 메모리를 할당한다는 점에 유의"
"하세요. 이 힙 할당에는 성능 오버헤드가 있습니다."
#: src/async/pitfalls/async-traits.md:54
msgid ""
"The challenges in language support for `async trait` are deep Rust and "
"probably not worth describing in-depth. Niko Matsakis did a good job of "
"explaining them in [this post](https://smallcultfollowing.com/babysteps/"
"blog/2019/10/26/async-fn-in-traits-are-hard/) if you are interested in "
"digging deeper."
msgstr ""
"`async trait` 를 언어 차원에서 지원하는 것과 관련된 문제는 매우 전문적인 토픽"
"이며 따라서 이 강의에서 다룰 내용은 아닙니다. [이 게시물](https://"
"smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-"
"hard/)에 이에 관한 니코 마사키스의 좋은 설명이 있으므로 관심이 있다면 참고하"
"세요."
#: src/async/pitfalls/async-traits.md:60
msgid ""
"Try creating a new sleeper struct that will sleep for a random amount of "
"time and adding it to the Vec."
msgstr ""
"임의의 시간 동안 sleep 하는 새로운 sleeper 구조체를 만들어 Vec에 추가해 보세"
"요."
#: src/async/pitfalls/cancellation.md:3
msgid ""
"Dropping a future implies it can never be polled again. This is called "
"_cancellation_ and it can occur at any `await` point. Care is needed to "
"ensure the system works correctly even when futures are cancelled. For "
"example, it shouldn't deadlock or lose data."
msgstr ""
#: src/async/pitfalls/cancellation.md:8
msgid ""
"```rust,editable,compile_fail\n"
"use std::io::{self, ErrorKind};\n"
"use std::time::Duration;\n"
"use tokio::io::{AsyncReadExt, AsyncWriteExt, DuplexStream};\n"
"\n"
"struct LinesReader {\n"
" stream: DuplexStream,\n"
"}\n"
"\n"
"impl LinesReader {\n"
" fn new(stream: DuplexStream) -> Self {\n"
" Self { stream }\n"
" }\n"
"\n"
" async fn next(&mut self) -> io::Result<Option<String>> {\n"
" let mut bytes = Vec::new();\n"
" let mut buf = [0];\n"
" while self.stream.read(&mut buf[..]).await? != 0 {\n"
" bytes.push(buf[0]);\n"
" if buf[0] == b'\\n' {\n"
" break;\n"
" }\n"
" }\n"
" if bytes.is_empty() {\n"
" return Ok(None)\n"
" }\n"
" let s = String::from_utf8(bytes)\n"
" .map_err(|_| io::Error::new(ErrorKind::InvalidData, \"not "
"UTF-8\"))?;\n"
" Ok(Some(s))\n"
" }\n"
"}\n"
"\n"
"async fn slow_copy(source: String, mut dest: DuplexStream) -> std::io::"
"Result<()> {\n"
" for b in source.bytes() {\n"
" dest.write_u8(b).await?;\n"
" tokio::time::sleep(Duration::from_millis(10)).await\n"
" }\n"
" Ok(())\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> std::io::Result<()> {\n"
" let (client, server) = tokio::io::duplex(5);\n"
" let handle = tokio::spawn(slow_copy(\"hi\\nthere\\n\".to_owned(), "
"client));\n"
"\n"
" let mut lines = LinesReader::new(server);\n"
" let mut interval = tokio::time::interval(Duration::from_millis(60));\n"
" loop {\n"
" tokio::select! {\n"
" _ = interval.tick() => println!(\"tick!\"),\n"
" line = lines.next() => if let Some(l) = line? {\n"
" print!(\"{}\", l)\n"
" } else {\n"
" break\n"
" },\n"
" }\n"
" }\n"
" handle.await.unwrap()?;\n"
" Ok(())\n"
"}\n"
"```"
msgstr ""
#: src/async/pitfalls/cancellation.md:72
msgid ""
"The compiler doesn't help with cancellation-safety. You need to read API "
"documentation and consider what state your `async fn` holds."
msgstr ""
#: src/async/pitfalls/cancellation.md:75
msgid ""
"Unlike `panic` and `?`, cancellation is part of normal control flow (vs "
"error-handling)."
msgstr ""
#: src/async/pitfalls/cancellation.md:78
msgid "The example loses parts of the string."
msgstr ""
#: src/async/pitfalls/cancellation.md:80
msgid ""
"Whenever the `tick()` branch finishes first, `next()` and its `buf` are "
"dropped."
msgstr ""
#: src/async/pitfalls/cancellation.md:82
msgid ""
"`LinesReader` can be made cancellation-safe by makeing `buf` part of the "
"struct:"
msgstr ""
#: src/async/pitfalls/cancellation.md:83
msgid ""
"```rust,compile_fail\n"
"struct LinesReader {\n"
" stream: DuplexStream,\n"
" bytes: Vec<u8>,\n"
" buf: [u8; 1],\n"
"}\n"
"\n"
"impl LinesReader {\n"
" fn new(stream: DuplexStream) -> Self {\n"
" Self { stream, bytes: Vec::new(), buf: [0] }\n"
" }\n"
" async fn next(&mut self) -> io::Result<Option<String>> {\n"
" // prefix buf and bytes with self.\n"
" // ...\n"
" let raw = std::mem::take(&mut self.bytes);\n"
" let s = String::from_utf8(raw)\n"
" // ...\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/async/pitfalls/cancellation.md:104
msgid ""
"[`Interval::tick`](https://docs.rs/tokio/latest/tokio/time/struct.Interval."
"html#method.tick) is cancellation-safe because it keeps track of whether a "
"tick has been 'delivered'."
msgstr ""
#: src/async/pitfalls/cancellation.md:107
msgid ""
"[`AsyncReadExt::read`](https://docs.rs/tokio/latest/tokio/io/trait."
"AsyncReadExt.html#method.read) is cancellation-safe because it either "
"returns or doesn't read data."
msgstr ""
#: src/async/pitfalls/cancellation.md:110
msgid ""
"[`AsyncBufReadExt::read_line`](https://docs.rs/tokio/latest/tokio/io/trait."
"AsyncBufReadExt.html#method.read_line) is similar to the example and _isn't_ "
"cancellation-safe. See its documentation for details and alternatives."
msgstr ""
#: src/exercises/concurrency/afternoon.md:3
msgid ""
"To practice your Async Rust skills, we have again two exercises for you:"
msgstr ""
#: src/exercises/concurrency/afternoon.md:5
msgid ""
"Dining philosophers: we already saw this problem in the morning. This time "
"you are going to implement it with Async Rust."
msgstr ""
#: src/exercises/concurrency/afternoon.md:8
msgid ""
"A Broadcast Chat Application: this is a larger project that allows you "
"experiment with more advanced Async Rust features."
msgstr ""
#: src/exercises/concurrency/dining-philosophers-async.md:1
#: src/exercises/concurrency/solutions-afternoon.md:3
#, fuzzy
msgid "Dining Philosophers - Async"
msgstr "식사하는 철학자들"
#: src/exercises/concurrency/dining-philosophers-async.md:3
msgid ""
"See [dining philosophers](dining-philosophers.md) for a description of the "
"problem."
msgstr ""
#: src/exercises/concurrency/dining-philosophers-async.md:6
#, fuzzy
msgid ""
"As before, you will need a local [Cargo installation](../../cargo/running-"
"locally.md) for this exercise. Copy the code below to a file called `src/"
"main.rs`, fill out the blanks, and test that `cargo run` does not deadlock:"
msgstr ""
"이번 훈련에서는 [카고 설치하기](../../cargo/running-locally.md)가 필요합니"
"다. 아래 코드를 복사해서 `src/main.rs`에 붙여놓고 빈 부분을 채우고, `cargo "
"run` 커맨드로 테스트 해서 교착상태(데드락)가 발생하지 않는지 확인합니다:"
#: src/exercises/concurrency/dining-philosophers-async.md:13
msgid ""
"```rust,compile_fail\n"
"use std::sync::Arc;\n"
"use tokio::time;\n"
"use tokio::sync::mpsc::{self, Sender};\n"
"use tokio::sync::Mutex;\n"
"\n"
"struct Fork;\n"
"\n"
"struct Philosopher {\n"
" name: String,\n"
" // left_fork: ...\n"
" // right_fork: ...\n"
" // thoughts: ...\n"
"}\n"
"\n"
"impl Philosopher {\n"
" async fn think(&self) {\n"
" self.thoughts\n"
" .send(format!(\"Eureka! {} has a new idea!\", &self.name))."
"await\n"
" .unwrap();\n"
" }\n"
"\n"
" async fn eat(&self) {\n"
" // Pick up forks...\n"
" println!(\"{} is eating...\", &self.name);\n"
" time::sleep(time::Duration::from_millis(5)).await;\n"
" }\n"
"}\n"
"\n"
"static PHILOSOPHERS: &[&str] =\n"
" &[\"Socrates\", \"Plato\", \"Aristotle\", \"Thales\", \"Pythagoras\"];\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" // Create forks\n"
"\n"
" // Create philosophers\n"
"\n"
" // Make them think and eat\n"
"\n"
" // Output their thoughts\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/dining-philosophers-async.md:57
msgid ""
"Since this time you are using Async Rust, you'll need a `tokio` dependency. "
"You can use the following `Cargo.toml`:"
msgstr ""
#: src/exercises/concurrency/dining-philosophers-async.md:62
msgid ""
"```toml\n"
"[package]\n"
"name = \"dining-philosophers-async-dine\"\n"
"version = \"0.1.0\"\n"
"edition = \"2021\"\n"
"\n"
"[dependencies]\n"
"tokio = {version = \"1.26.0\", features = [\"sync\", \"time\", \"macros\", "
"\"rt-multi-thread\"]}\n"
"```"
msgstr ""
#: src/exercises/concurrency/dining-philosophers-async.md:72
msgid ""
"Also note that this time you have to use the `Mutex` and the `mpsc` module "
"from the `tokio` crate."
msgstr ""
#: src/exercises/concurrency/dining-philosophers-async.md:77
msgid "Can you make your implementation single-threaded? "
msgstr ""
#: src/exercises/concurrency/chat-app.md:3
msgid ""
"In this exercise, we want to use our new knowledge to implement a broadcast "
"chat application. We have a chat server that the clients connect to and "
"publish their messages. The client reads user messages from the standard "
"input, and sends them to the server. The chat server broadcasts each message "
"that it receives to all the clients."
msgstr ""
#: src/exercises/concurrency/chat-app.md:9
msgid ""
"For this, we use [a broadcast channel](https://docs.rs/tokio/latest/tokio/"
"sync/broadcast/fn.channel.html) on the server, and [`tokio_websockets`]"
"(https://docs.rs/tokio-websockets/0.3.2/tokio_websockets/) for the "
"communication between the client and the server."
msgstr ""
#: src/exercises/concurrency/chat-app.md:13
msgid "Create a new Cargo project and add the following dependencies:"
msgstr ""
#: src/exercises/concurrency/chat-app.md:15
msgid "`Cargo.toml`:"
msgstr ""
#: src/exercises/concurrency/chat-app.md:19
msgid ""
"```toml\n"
"[package]\n"
"name = \"chat-async\"\n"
"version = \"0.1.0\"\n"
"edition = \"2021\"\n"
"\n"
"[dependencies]\n"
"futures-util = \"0.3.28\"\n"
"http = \"0.2.9\"\n"
"tokio = { version = \"1.28.1\", features = [\"full\"] }\n"
"tokio-websockets = \"0.3.2\"\n"
"```"
msgstr ""
#: src/exercises/concurrency/chat-app.md:32
msgid "The required APIs"
msgstr ""
#: src/exercises/concurrency/chat-app.md:33
msgid ""
"You are going to need the following functions from `tokio` and "
"[`tokio_websockets`](https://docs.rs/tokio-websockets/0.3.2/"
"tokio_websockets/). Spend a few minutes to familiarize yourself with the "
"API. "
msgstr ""
#: src/exercises/concurrency/chat-app.md:37
msgid ""
"[WebsocketStream::next()](https://docs.rs/tokio-websockets/0.3.2/"
"tokio_websockets/proto/struct.WebsocketStream.html#method.next): for "
"asynchronously reading messages from a Websocket Stream."
msgstr ""
#: src/exercises/concurrency/chat-app.md:39
msgid ""
"[SinkExt::send()](https://docs.rs/futures-util/0.3.28/futures_util/sink/"
"trait.SinkExt.html#method.send) implemented by `WebsocketStream`: for "
"asynchronously sending messages on a Websocket Stream."
msgstr ""
#: src/exercises/concurrency/chat-app.md:41
msgid ""
"[Lines::next_line()](https://docs.rs/tokio/latest/tokio/io/struct.Lines."
"html#method.next_line): for asynchronously reading user messages from the "
"standard input."
msgstr ""
#: src/exercises/concurrency/chat-app.md:43
msgid ""
"[Sender::subscribe()](https://docs.rs/tokio/latest/tokio/sync/broadcast/"
"struct.Sender.html#method.subscribe): for subscribing to a broadcast channel."
msgstr ""
#: src/exercises/concurrency/chat-app.md:46
#, fuzzy
msgid "Two binaries"
msgstr "러스트 바이너리"
#: src/exercises/concurrency/chat-app.md:48
msgid ""
"Normally in a Cargo project, you can have only one binary, and one `src/main."
"rs` file. In this project, we need two binaries. One for the client, and one "
"for the server. You could potentially make them two separate Cargo projects, "
"but we are going to put them in a single Cargo project with two binaries. "
"For this to work, the client and the server code should go under `src/bin` "
"(see the [documentation](https://doc.rust-lang.org/cargo/reference/cargo-"
"targets.html#binaries)). "
msgstr ""
#: src/exercises/concurrency/chat-app.md:55
msgid ""
"Copy the following server and client code into `src/bin/server.rs` and `src/"
"bin/client.rs`, respectively. Your task is to complete these files as "
"described below. "
msgstr ""
#: src/exercises/concurrency/chat-app.md:59
#: src/exercises/concurrency/solutions-afternoon.md:123
msgid "`src/bin/server.rs`:"
msgstr ""
#: src/exercises/concurrency/chat-app.md:63
msgid ""
"```rust,compile_fail\n"
"use futures_util::sink::SinkExt;\n"
"use std::error::Error;\n"
"use std::net::SocketAddr;\n"
"use tokio::net::{TcpListener, TcpStream};\n"
"use tokio::sync::broadcast::{channel, Sender};\n"
"use tokio_websockets::{Message, ServerBuilder, WebsocketStream};\n"
"\n"
"async fn handle_connection(\n"
" addr: SocketAddr,\n"
" mut ws_stream: WebsocketStream<TcpStream>,\n"
" bcast_tx: Sender<String>,\n"
") -> Result<(), Box<dyn Error + Send + Sync>> {\n"
"\n"
" // TODO: For a hint, see the description of the task below.\n"
"\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {\n"
" let (bcast_tx, _) = channel(16);\n"
"\n"
" let listener = TcpListener::bind(\"127.0.0.1:2000\").await?;\n"
" println!(\"listening on port 2000\");\n"
"\n"
" loop {\n"
" let (socket, addr) = listener.accept().await?;\n"
" println!(\"New connection from {addr:?}\");\n"
" let bcast_tx = bcast_tx.clone();\n"
" tokio::spawn(async move {\n"
" // Wrap the raw TCP stream into a websocket.\n"
" let ws_stream = ServerBuilder::new().accept(socket).await?;\n"
"\n"
" handle_connection(addr, ws_stream, bcast_tx).await\n"
" });\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/chat-app.md:102
#: src/exercises/concurrency/solutions-afternoon.md:208
msgid "`src/bin/client.rs`:"
msgstr ""
#: src/exercises/concurrency/chat-app.md:106
msgid ""
"```rust,compile_fail\n"
"use futures_util::SinkExt;\n"
"use http::Uri;\n"
"use tokio::io::{AsyncBufReadExt, BufReader};\n"
"use tokio_websockets::{ClientBuilder, Message};\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> Result<(), tokio_websockets::Error> {\n"
" let mut ws_stream = ClientBuilder::from_uri(Uri::"
"from_static(\"ws://127.0.0.1:2000\"))\n"
" .connect()\n"
" .await?;\n"
"\n"
" let stdin = tokio::io::stdin();\n"
" let mut stdin = BufReader::new(stdin).lines();\n"
"\n"
"\n"
" // TODO: For a hint, see the description of the task below.\n"
"\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/chat-app.md:127
#, fuzzy
msgid "Running the binaries"
msgstr "강의 진행 방식"
#: src/exercises/concurrency/chat-app.md:128
#, fuzzy
msgid "Run the server with:"
msgstr "아래 명령어로 예제 코드를 실행하세요."
#: src/exercises/concurrency/chat-app.md:130
#, fuzzy
msgid ""
"```shell\n"
"cargo run --bin server\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin pac\n"
"```"
#: src/exercises/concurrency/chat-app.md:134
#, fuzzy
msgid "and the client with:"
msgstr "아래 명령어로 예제 코드를 실행하세요."
#: src/exercises/concurrency/chat-app.md:136
#, fuzzy
msgid ""
"```shell\n"
"cargo run --bin client\n"
"```"
msgstr ""
"```sh\n"
"cargo embed --bin pac\n"
"```"
#: src/exercises/concurrency/chat-app.md:142
msgid "Implement the `handle_connection` function in `src/bin/server.rs`."
msgstr ""
#: src/exercises/concurrency/chat-app.md:143
msgid ""
"Hint: Use `tokio::select!` for concurrently performing two tasks in a "
"continuous loop. One task receives messages from the client and broadcasts "
"them. The other sends messages received by the server to the client."
msgstr ""
#: src/exercises/concurrency/chat-app.md:146
msgid "Complete the main function in `src/bin/client.rs`."
msgstr ""
#: src/exercises/concurrency/chat-app.md:147
msgid ""
"Hint: As before, use `tokio::select!` in a continuous loop for concurrently "
"performing two tasks: (1) reading user messages from standard input and "
"sending them to the server, and (2) receiving messages from the server, and "
"displaying them for the user."
msgstr ""
#: src/exercises/concurrency/chat-app.md:151
msgid ""
"Optional: Once you are done, change the code to broadcast messages to all "
"clients, but the sender of the message."
msgstr ""
#: src/thanks.md:3
msgid ""
"_Thank you for taking Comprehensive Rust 🦀!_ We hope you enjoyed it and "
"that it was useful."
msgstr ""
"Comprehensive Rust 🦀를 이용해 주셔서 감사합니다. 즐겁고 유익한 시간이었기를 "
"바랍니다."
#: src/thanks.md:6
msgid ""
"We've had a lot of fun putting the course together. The course is not "
"perfect, so if you spotted any mistakes or have ideas for improvements, "
"please get in [contact with us on GitHub](https://github.com/google/"
"comprehensive-rust/discussions). We would love to hear from you."
msgstr ""
"강의가 완벽하진 않으니 실수나 개선점이 있다면 언제든지 [깃허브](https://"
"github.com/google/comprehensive-rust/discussions)로 연락주세요."
#: src/other-resources.md:1
msgid "Other Rust Resources"
msgstr "러스트 참고 자료"
#: src/other-resources.md:3
msgid ""
"The Rust community has created a wealth of high-quality and free resources "
"online."
msgstr "러스트 커뮤니티는 온라인에서 고품질의 무료 소스를 만들었습니다."
#: src/other-resources.md:6
msgid "Official Documentation"
msgstr "공식 문서들"
#: src/other-resources.md:8
msgid "The Rust project hosts many resources. These cover Rust in general:"
msgstr ""
"러스트 프로젝트에는 참조할 만한 자료가 많습니다. 일반적인 내용을 다루는 몇가"
"지 참고 문서들입니다:"
#: src/other-resources.md:10
msgid ""
"[The Rust Programming Language](https://doc.rust-lang.org/book/): the "
"canonical free book about Rust. Covers the language in detail and includes a "
"few projects for people to build."
msgstr ""
"[The Rust Programming Language](https://doc.rust-lang.org/book/): 러스트에 대"
"한 무료 표준 서적입니다. 언어에 대한 자세한 설명과 사람들이 빌드 할수 있는 몇"
"가지 프로젝트를 포함합니다."
#: src/other-resources.md:13
msgid ""
"[Rust By Example](https://doc.rust-lang.org/rust-by-example/): covers the "
"Rust syntax via a series of examples which showcase different constructs. "
"Sometimes includes small exercises where you are asked to expand on the code "
"in the examples."
msgstr ""
"[Rust By Example](https://doc.rust-lang.org/rust-by-example/): 여러 예제를 통"
"해 러스트의 문법을 보여주며 때때로 코드를 확장하는 약간의 연습문제들이 포함되"
"어 있습니다."
#: src/other-resources.md:17
msgid ""
"[Rust Standard Library](https://doc.rust-lang.org/std/): full documentation "
"of the standard library for Rust."
msgstr ""
"[Rust Standard Library](https://doc.rust-lang.org/std/): 러스트 표준 라이브러"
"리 전체 문서입니다."
#: src/other-resources.md:19
msgid ""
"[The Rust Reference](https://doc.rust-lang.org/reference/): an incomplete "
"book which describes the Rust grammar and memory model."
msgstr ""
"[The Rust Reference](https://doc.rust-lang.org/reference/): 메모리 모델링과 "
"러스트 문법을 설명하는 문서입니다.(아직 불완전하다함)"
#: src/other-resources.md:22
msgid "More specialized guides hosted on the official Rust site:"
msgstr "좀 더 전문적인 공식 가이드입니다:"
#: src/other-resources.md:24
msgid ""
"[The Rustonomicon](https://doc.rust-lang.org/nomicon/): covers unsafe Rust, "
"including working with raw pointers and interfacing with other languages "
"(FFI)."
msgstr ""
"[The Rustonomicon](https://doc.rust-lang.org/nomicon/): 안전하지 않은 러스"
"트, FFI, raw포인터 작업을 다룹니다."
#: src/other-resources.md:27
msgid ""
"[Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/): "
"covers the new asynchronous programming model which was introduced after the "
"Rust Book was written."
msgstr ""
"[Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/): "
"러스트 북이 작성 된 이후 도입된 새로운 비동기 프로그래밍 모델을 다룹니다."
#: src/other-resources.md:30
msgid ""
"[The Embedded Rust Book](https://doc.rust-lang.org/stable/embedded-book/): "
"an introduction to using Rust on embedded devices without an operating "
"system."
msgstr ""
"[The Embedded Rust Book](https://doc.rust-lang.org/stable/embedded-book/): 운"
"영체제가 없는 임베디드 장치에서의 러스트 사용법을 소개합니다."
#: src/other-resources.md:33
msgid "Unofficial Learning Material"
msgstr "비공식적 학습 자료"
#: src/other-resources.md:35
msgid "A small selection of other guides and tutorial for Rust:"
msgstr "러스트에 대한 기타 안내서와 튜토리얼의 일부입니다:"
#: src/other-resources.md:37
msgid ""
"[Learn Rust the Dangerous Way](http://cliffle.com/p/dangerust/): covers Rust "
"from the perspective of low-level C programmers."
msgstr ""
"[Learn Rust the Dangerous Way](http://cliffle.com/p/dangerust/): C언어 프로그"
"래머 관점에서 러스트를 다룹니다."
#: src/other-resources.md:39
msgid ""
"[Rust for Embedded C Programmers](https://docs.opentitan.org/doc/ug/"
"rust_for_c/): covers Rust from the perspective of developers who write "
"firmware in C."
msgstr ""
"[Rust for Embedded C Programmers](https://docs.opentitan.org/doc/ug/"
"rust_for_c/): 임베디드 C개발자(펌웨어 개발자)를 위한 러스트 가이드입니다."
#: src/other-resources.md:42
msgid ""
"[Rust for professionals](https://overexact.com/rust-for-professionals/): "
"covers the syntax of Rust using side-by-side comparisons with other "
"languages such as C, C++, Java, JavaScript, and Python."
msgstr ""
"[Rust for professionals](https://overexact.com/rust-for-professionals/): 다"
"른 언어(C/C++, Java, Python, Javascript)와의 병렬비교를 사용하여 러스트 문법"
"을 다룹니다."
#: src/other-resources.md:45
msgid ""
"[Rust on Exercism](https://exercism.org/tracks/rust): 100+ exercises to help "
"you learn Rust."
msgstr ""
"[Rust on Exercism](https://exercism.org/tracks/rust): 러스트를 배우는데 도움"
"이 되는 100개 이상의 연습문제"
#: src/other-resources.md:47
msgid ""
"[Ferrous Teaching Material](https://ferrous-systems.github.io/teaching-"
"material/index.html): a series of small presentations covering both basic "
"and advanced part of the Rust language. Other topics such as WebAssembly, "
"and async/await are also covered."
msgstr ""
"[Ferrous Teaching Material](https://ferrous-systems.github.io/teaching-"
"material/index.html): 러스트 언어의 기본부터 고급을 전부 다루는 일련의 작은 "
"프레젠테이션, 웹 어셈블리, async/await 같은 부분도 함께 다룹니다."
#: src/other-resources.md:52
msgid ""
"[Beginner's Series to Rust](https://docs.microsoft.com/en-us/shows/beginners-"
"series-to-rust/) and [Take your first steps with Rust](https://docs."
"microsoft.com/en-us/learn/paths/rust-first-steps/): two Rust guides aimed at "
"new developers. The first is a set of 35 videos and the second is a set of "
"11 modules which covers Rust syntax and basic constructs."
msgstr ""
"[Beginner's Series to Rust](https://docs.microsoft.com/en-us/shows/beginners-"
"series-to-rust/), [Take your first steps with Rust](https://docs.microsoft."
"com/en-us/learn/paths/rust-first-steps/): 첫번째는 35개의 시리즈 영상이며 두"
"번째는 러스트의 문법과 구조를 다루는 11개의 모듈 세트입니다."
#: src/other-resources.md:58
msgid ""
"[Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial."
"github.io/too-many-lists/): in-depth exploration of Rust's memory management "
"rules, through implementing a few different types of list structures."
msgstr ""
"[Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial."
"github.io/too-many-lists/): 몇가지 유형의 리스트 자료구조를 구현해보면서 러스"
"트의 메모리 관리 규칙들을 깊이있게 탐색합니다."
#: src/other-resources.md:63
msgid ""
"Please see the [Little Book of Rust Books](https://lborb.github.io/book/) "
"for even more Rust books."
msgstr ""
"[Little Book of Rust Books](https://lborb.github.io/book/)에서 더 많은 러스"
"트 북을 확인해보세요."
#: src/credits.md:3
msgid ""
"The material here builds on top of the many great sources of Rust "
"documentation. See the page on [other resources](other-resources.md) for a "
"full list of useful resources."
msgstr ""
"이 자료는 많은 훌륭한 러스트 문서들의 도움을 받아 작성되었습니다. 유용한 자료"
"의 전체 목록은 [other resources](other-resources.md)에서 살펴보시기 바랍니다."
#: src/credits.md:7
#, fuzzy
msgid ""
"The material of Comprehensive Rust is licensed under the terms of the Apache "
"2.0 license, please see [`LICENSE`](https://github.com/google/comprehensive-"
"rust/blob/main/LICENSE) for details."
msgstr ""
"Comprehensive Rust의 자료는 Apache 2.0 라이선스를 따릅니다. 자세한건 "
"[`LICENSE`](../LICENSE) 확인해 보시기 바랍니다."
#: src/credits.md:12
msgid "Rust by Example"
msgstr "Rust by Example"
#: src/credits.md:14
msgid ""
"Some examples and exercises have been copied and adapted from [Rust by "
"Example](https://doc.rust-lang.org/rust-by-example/). Please see the "
"`third_party/rust-by-example/` directory for details, including the license "
"terms."
msgstr ""
"일부 예제와 연습문제는 [Rust by Example](https://doc.rust-lang.org/rust-by-"
"example/)을 참조하였습니다. 라이선스 조항을 포함하여 저장소의 `third_party/"
"rust-by-example/` 폴더를 참조하시기 바랍니다."
#: src/credits.md:19
msgid "Rust on Exercism"
msgstr "Rust on Exercism"
#: src/credits.md:21
msgid ""
"Some exercises have been copied and adapted from [Rust on Exercism](https://"
"exercism.org/tracks/rust). Please see the `third_party/rust-on-exercism/` "
"directory for details, including the license terms."
msgstr ""
"일부 연습문제는 [Rust on Exercism](https://exercism.org/tracks/rust)을 참조하"
"였습니다. 라이선스 조항을 포함하여 저장소의 `third_party/rust-on-exercism/`폴"
"더를 참조하시기 바랍니다."
#: src/credits.md:26
msgid "CXX"
msgstr "CXX"
#: src/credits.md:28
msgid ""
"The [Interoperability with C++](android/interoperability/cpp.md) section "
"uses an image from [CXX](https://cxx.rs/). Please see the `third_party/cxx/` "
"directory for details, including the license terms."
msgstr ""
"4일차 오후 강의 중 [Interoperability with C++](android/interoperability/cpp."
"md)에서는 [CXX](https://cxx.rs/)의 이미지를 사용하였습니다. 라이선스 조항을 "
"포함하여 저장소의 `third_party/cxx/`폴더를 참조하시기 바랍니다."
#: src/exercises/solutions.md:3
msgid "You will find solutions to the exercises on the following pages."
msgstr "연습문제의 해답은 다음 페이지에서 확인할 수 있습니다."
#: src/exercises/solutions.md:5
msgid ""
"Feel free to ask questions about the solutions [on GitHub](https://github."
"com/google/comprehensive-rust/discussions). Let us know if you have a "
"different or better solution than what is presented here."
msgstr ""
"[깃허브](https://github.com/google/comprehensive-rust/discussions)에서 이에 "
"대해 자유롭게 질문하시고 더 나은 솔루션이 있다면 알려주시기 바랍니다."
#: src/exercises/solutions.md:10
msgid ""
"**Note:** Please ignore the `// ANCHOR: label` and `// ANCHOR_END: label` "
"comments you see in the solutions. They are there to make it possible to re-"
"use parts of the solutions as the exercises."
msgstr ""
"**참고:** `// ANCHOR: label`과 `// ANCHOR_END: label` 주석은 문제를 구성하기 "
"위한 메타 주석으로 무시하시면 됩니다."
#: src/exercises/day-1/solutions-morning.md:1
msgid "Day 1 Morning Exercises"
msgstr "1일차 오전 연습문제"
#: src/exercises/day-1/solutions-morning.md:5
msgid "([back to exercise](for-loops.md))"
msgstr ""
#: src/exercises/day-1/solutions-morning.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: transpose\n"
"fn transpose(matrix: [[i32; 3]; 3]) -> [[i32; 3]; 3] {\n"
" // ANCHOR_END: transpose\n"
" let mut result = [[0; 3]; 3];\n"
" for i in 0..3 {\n"
" for j in 0..3 {\n"
" result[j][i] = matrix[i][j];\n"
" }\n"
" }\n"
" return result;\n"
"}\n"
"\n"
"// ANCHOR: pretty_print\n"
"fn pretty_print(matrix: &[[i32; 3]; 3]) {\n"
" // ANCHOR_END: pretty_print\n"
" for row in matrix {\n"
" println!(\"{row:?}\");\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: tests\n"
"#[test]\n"
"fn test_transpose() {\n"
" let matrix = [\n"
" [101, 102, 103], //\n"
" [201, 202, 203],\n"
" [301, 302, 303],\n"
" ];\n"
" let transposed = transpose(matrix);\n"
" assert_eq!(\n"
" transposed,\n"
" [\n"
" [101, 201, 301], //\n"
" [102, 202, 302],\n"
" [103, 203, 303],\n"
" ]\n"
" );\n"
"}\n"
"// ANCHOR_END: tests\n"
"\n"
"// ANCHOR: main\n"
"fn main() {\n"
" let matrix = [\n"
" [101, 102, 103], // <-- the comment makes rustfmt add a newline\n"
" [201, 202, 203],\n"
" [301, 302, 303],\n"
" ];\n"
"\n"
" println!(\"matrix:\");\n"
" pretty_print(&matrix);\n"
"\n"
" let transposed = transpose(matrix);\n"
" println!(\"transposed:\");\n"
" pretty_print(&transposed);\n"
"}\n"
"```"
msgstr ""
#: src/exercises/day-1/solutions-morning.md:78
msgid "Bonus question"
msgstr "보너스 문제"
#: src/exercises/day-1/solutions-morning.md:80
msgid ""
"It requires more advanced concepts. It might seem that we could use a slice-"
"of-slices (`&[&[i32]]`) as the input type to transpose and thus make our "
"function handle any size of matrix. However, this quickly breaks down: the "
"return type cannot be `&[&[i32]]` since it needs to own the data you return."
msgstr ""
"사실 이 문제는 고급 개념이 필요합니다. 슬라이스의 슬라이스(slice-of-slices, "
"`&[&[i32]]`)를 입력 타입으로 사용하면 모든 크기의 행렬을 처리할 수 있을것 같"
"습니다. 하지만 실제로 해보면 금방 안된다는 걸 알 수 있습니다. 반환값을 소유해"
"야 하기때문에 `&[&[i32]]` 반환 타입으로 사용할 수 없습니다."
#: src/exercises/day-1/solutions-morning.md:82
msgid ""
"You can attempt to use something like `Vec<Vec<i32>>`, but this doesn't work "
"out-of-the-box either: it's hard to convert from `Vec<Vec<i32>>` to "
"`&[&[i32]]` so now you cannot easily use `pretty_print` either."
msgstr ""
"`Vec<Vec<i32>>`와 같은 타입을 사용하려고 시도할 수도 있지만 역시 쉽게 되진 않"
"습니다. `Vec<Vec<i32>>` 타입을 `&[&[i32]]`로 변환하는 것이 어렵기 때문에 "
"`pretty_print`을 사용하는데 어려움이 있습니다."
#: src/exercises/day-1/solutions-morning.md:84
msgid ""
"Once we get to traits and generics, we'll be able to use the [`std::convert::"
"AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) trait to "
"abstract over anything that can be referenced as a slice."
msgstr ""
"트레잇나 제네릭을 다루고 나면 [`std::convert::AsRef`](https://doc.rust-lang."
"org/std/convert/trait.AsRef.html) 트레잇을 사용하여 슬라이스처럼 사용될 수 있"
"는 타입을 추상화할 수 있습니다."
#: src/exercises/day-1/solutions-morning.md:86
msgid ""
"```rust\n"
"use std::convert::AsRef;\n"
"use std::fmt::Debug;\n"
"\n"
"fn pretty_print<T, Line, Matrix>(matrix: Matrix)\n"
"where\n"
" T: Debug,\n"
" // A line references a slice of items\n"
" Line: AsRef<[T]>,\n"
" // A matrix references a slice of lines\n"
" Matrix: AsRef<[Line]>\n"
"{\n"
" for row in matrix.as_ref() {\n"
" println!(\"{:?}\", row.as_ref());\n"
" }\n"
"}\n"
"\n"
"fn main() {\n"
" // &[&[i32]]\n"
" pretty_print(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]);\n"
" // [[&str; 2]; 2]\n"
" pretty_print([[\"a\", \"b\"], [\"c\", \"d\"]]);\n"
" // Vec<Vec<i32>>\n"
" pretty_print(vec![vec![1, 2], vec![3, 4]]);\n"
"}\n"
"```"
msgstr ""
#: src/exercises/day-1/solutions-morning.md:113
msgid ""
"In addition, the type itself would not enforce that the child slices are of "
"the same length, so such variable could contain an invalid matrix."
msgstr ""
"또한, 슬라이스 타입은 길이를 포함하지 않기 때문에 한 단계 아래의 슬라이스들"
"이 같은 길이임을 보장할 수 없습니다. 때문에 슬라이스 타입의 변수에는 잘못된 "
"행렬이 전달될 수 있습니다."
#: src/exercises/day-1/solutions-afternoon.md:1
msgid "Day 1 Afternoon Exercises"
msgstr "1일차 오후 연습문제"
#: src/exercises/day-1/solutions-afternoon.md:3
msgid "Designing a Library"
msgstr "도서관 설계"
#: src/exercises/day-1/solutions-afternoon.md:5
msgid "([back to exercise](book-library.md))"
msgstr ""
#: src/exercises/day-1/solutions-afternoon.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: setup\n"
"struct Library {\n"
" books: Vec<Book>,\n"
"}\n"
"\n"
"struct Book {\n"
" title: String,\n"
" year: u16,\n"
"}\n"
"\n"
"impl Book {\n"
" // This is a constructor, used below.\n"
" fn new(title: &str, year: u16) -> Book {\n"
" Book {\n"
" title: String::from(title),\n"
" year,\n"
" }\n"
" }\n"
"}\n"
"\n"
"// Implement the methods below. Update the `self` parameter to\n"
"// indicate the method's required level of ownership over the object:\n"
"//\n"
"// - `&self` for shared read-only access,\n"
"// - `&mut self` for unique and mutable access,\n"
"// - `self` for unique access by value.\n"
"impl Library {\n"
" // ANCHOR_END: setup\n"
"\n"
" // ANCHOR: Library_new\n"
" fn new() -> Library {\n"
" // ANCHOR_END: Library_new\n"
" Library { books: Vec::new() }\n"
" }\n"
"\n"
" // ANCHOR: Library_len\n"
" //fn len(self) -> usize {\n"
" // todo!(\"Return the length of `self.books`\")\n"
" //}\n"
" // ANCHOR_END: Library_len\n"
" fn len(&self) -> usize {\n"
" self.books.len()\n"
" }\n"
"\n"
" // ANCHOR: Library_is_empty\n"
" //fn is_empty(self) -> bool {\n"
" // todo!(\"Return `true` if `self.books` is empty\")\n"
" //}\n"
" // ANCHOR_END: Library_is_empty\n"
" fn is_empty(&self) -> bool {\n"
" self.books.is_empty()\n"
" }\n"
"\n"
" // ANCHOR: Library_add_book\n"
" //fn add_book(self, book: Book) {\n"
" // todo!(\"Add a new book to `self.books`\")\n"
" //}\n"
" // ANCHOR_END: Library_add_book\n"
" fn add_book(&mut self, book: Book) {\n"
" self.books.push(book)\n"
" }\n"
"\n"
" // ANCHOR: Library_print_books\n"
" //fn print_books(self) {\n"
" // todo!(\"Iterate over `self.books` and each book's title and "
"year\")\n"
" //}\n"
" // ANCHOR_END: Library_print_books\n"
" fn print_books(&self) {\n"
" for book in &self.books {\n"
" println!(\"{}, published in {}\", book.title, book.year);\n"
" }\n"
" }\n"
"\n"
" // ANCHOR: Library_oldest_book\n"
" //fn oldest_book(self) -> Option<&Book> {\n"
" // todo!(\"Return a reference to the oldest book (if any)\")\n"
" //}\n"
" // ANCHOR_END: Library_oldest_book\n"
" fn oldest_book(&self) -> Option<&Book> {\n"
" // Using a closure and a built-in method:\n"
" // self.books.iter().min_by_key(|book| book.year)\n"
"\n"
" // Longer hand-written solution:\n"
" let mut oldest: Option<&Book> = None;\n"
" for book in self.books.iter() {\n"
" if oldest.is_none() || book.year < oldest.unwrap().year {\n"
" oldest = Some(book);\n"
" }\n"
" }\n"
"\n"
" oldest\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: main\n"
"// This shows the desired behavior. Uncomment the code below and\n"
"// implement the missing methods. You will need to update the\n"
"// method signatures, including the \"self\" parameter! You may\n"
"// also need to update the variable bindings within main.\n"
"fn main() {\n"
" let library = Library::new();\n"
"\n"
" //println!(\"The library is empty: library.is_empty() -> {}\", library."
"is_empty());\n"
" //\n"
" //library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" //library.add_book(Book::new(\"Alice's Adventures in Wonderland\", "
"1865));\n"
" //\n"
" //println!(\"The library is no longer empty: library.is_empty() -> {}\", "
"library.is_empty());\n"
" //\n"
" //\n"
" //library.print_books();\n"
" //\n"
" //match library.oldest_book() {\n"
" // Some(book) => println!(\"The oldest book is {}\", book.title),\n"
" // None => println!(\"The library is empty!\"),\n"
" //}\n"
" //\n"
" //println!(\"The library has {} books\", library.len());\n"
" //library.print_books();\n"
"}\n"
"// ANCHOR_END: main\n"
"\n"
"#[test]\n"
"fn test_library_len() {\n"
" let mut library = Library::new();\n"
" assert_eq!(library.len(), 0);\n"
" assert!(library.is_empty());\n"
"\n"
" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", "
"1865));\n"
" assert_eq!(library.len(), 2);\n"
" assert!(!library.is_empty());\n"
"}\n"
"\n"
"#[test]\n"
"fn test_library_is_empty() {\n"
" let mut library = Library::new();\n"
" assert!(library.is_empty());\n"
"\n"
" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" assert!(!library.is_empty());\n"
"}\n"
"\n"
"#[test]\n"
"fn test_library_print_books() {\n"
" let mut library = Library::new();\n"
" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", "
"1865));\n"
" // We could try and capture stdout, but let us just call the\n"
" // method to start with.\n"
" library.print_books();\n"
"}\n"
"\n"
"#[test]\n"
"fn test_library_oldest_book() {\n"
" let mut library = Library::new();\n"
" assert!(library.oldest_book().is_none());\n"
"\n"
" library.add_book(Book::new(\"Lord of the Rings\", 1954));\n"
" assert_eq!(\n"
" library.oldest_book().map(|b| b.title.as_str()),\n"
" Some(\"Lord of the Rings\")\n"
" );\n"
"\n"
" library.add_book(Book::new(\"Alice's Adventures in Wonderland\", "
"1865));\n"
" assert_eq!(\n"
" library.oldest_book().map(|b| b.title.as_str()),\n"
" Some(\"Alice's Adventures in Wonderland\")\n"
" );\n"
"}\n"
"```"
msgstr ""
#: src/exercises/day-2/solutions-morning.md:1
msgid "Day 2 Morning Exercises"
msgstr "2일차 오전 연습문제"
#: src/exercises/day-2/solutions-morning.md:5
msgid "([back to exercise](points-polygons.md))"
msgstr ""
#: src/exercises/day-2/solutions-morning.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"#[derive(Debug, Copy, Clone, PartialEq, Eq)]\n"
"// ANCHOR: Point\n"
"pub struct Point {\n"
" // ANCHOR_END: Point\n"
" x: i32,\n"
" y: i32,\n"
"}\n"
"\n"
"// ANCHOR: Point-impl\n"
"impl Point {\n"
" // ANCHOR_END: Point-impl\n"
" pub fn new(x: i32, y: i32) -> Point {\n"
" Point { x, y }\n"
" }\n"
"\n"
" pub fn magnitude(self) -> f64 {\n"
" f64::from(self.x.pow(2) + self.y.pow(2)).sqrt()\n"
" }\n"
"\n"
" pub fn dist(self, other: Point) -> f64 {\n"
" (self - other).magnitude()\n"
" }\n"
"}\n"
"\n"
"impl std::ops::Add for Point {\n"
" type Output = Self;\n"
"\n"
" fn add(self, other: Self) -> Self::Output {\n"
" Self {\n"
" x: self.x + other.x,\n"
" y: self.y + other.y,\n"
" }\n"
" }\n"
"}\n"
"\n"
"impl std::ops::Sub for Point {\n"
" type Output = Self;\n"
"\n"
" fn sub(self, other: Self) -> Self::Output {\n"
" Self {\n"
" x: self.x - other.x,\n"
" y: self.y - other.y,\n"
" }\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Polygon\n"
"pub struct Polygon {\n"
" // ANCHOR_END: Polygon\n"
" points: Vec<Point>,\n"
"}\n"
"\n"
"// ANCHOR: Polygon-impl\n"
"impl Polygon {\n"
" // ANCHOR_END: Polygon-impl\n"
" pub fn new() -> Polygon {\n"
" Polygon { points: Vec::new() }\n"
" }\n"
"\n"
" pub fn add_point(&mut self, point: Point) {\n"
" self.points.push(point);\n"
" }\n"
"\n"
" pub fn left_most_point(&self) -> Option<Point> {\n"
" self.points.iter().min_by_key(|p| p.x).copied()\n"
" }\n"
"\n"
" pub fn iter(&self) -> impl Iterator<Item = &Point> {\n"
" self.points.iter()\n"
" }\n"
"\n"
" pub fn length(&self) -> f64 {\n"
" if self.points.is_empty() {\n"
" return 0.0;\n"
" }\n"
"\n"
" let mut result = 0.0;\n"
" let mut last_point = self.points[0];\n"
" for point in &self.points[1..] {\n"
" result += last_point.dist(*point);\n"
" last_point = *point;\n"
" }\n"
" result += last_point.dist(self.points[0]);\n"
" result\n"
" // Alternatively, Iterator::zip() lets us iterate over the points as "
"pairs\n"
" // but we need to pair each point with the next one, and the last "
"point\n"
" // with the first point. The zip() iterator is finished as soon as "
"one of \n"
" // the source iterators is finished, a neat trick is to combine "
"Iterator::cycle\n"
" // with Iterator::skip to create the second iterator for the zip and "
"using map \n"
" // and sum to calculate the total length.\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Circle\n"
"pub struct Circle {\n"
" // ANCHOR_END: Circle\n"
" center: Point,\n"
" radius: i32,\n"
"}\n"
"\n"
"// ANCHOR: Circle-impl\n"
"impl Circle {\n"
" // ANCHOR_END: Circle-impl\n"
" pub fn new(center: Point, radius: i32) -> Circle {\n"
" Circle { center, radius }\n"
" }\n"
"\n"
" pub fn circumference(&self) -> f64 {\n"
" 2.0 * std::f64::consts::PI * f64::from(self.radius)\n"
" }\n"
"\n"
" pub fn dist(&self, other: &Self) -> f64 {\n"
" self.center.dist(other.center)\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Shape\n"
"pub enum Shape {\n"
" Polygon(Polygon),\n"
" Circle(Circle),\n"
"}\n"
"// ANCHOR_END: Shape\n"
"\n"
"impl From<Polygon> for Shape {\n"
" fn from(poly: Polygon) -> Self {\n"
" Shape::Polygon(poly)\n"
" }\n"
"}\n"
"\n"
"impl From<Circle> for Shape {\n"
" fn from(circle: Circle) -> Self {\n"
" Shape::Circle(circle)\n"
" }\n"
"}\n"
"\n"
"impl Shape {\n"
" pub fn perimeter(&self) -> f64 {\n"
" match self {\n"
" Shape::Polygon(poly) => poly.length(),\n"
" Shape::Circle(circle) => circle.circumference(),\n"
" }\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: unit-tests\n"
"#[cfg(test)]\n"
"mod tests {\n"
" use super::*;\n"
"\n"
" fn round_two_digits(x: f64) -> f64 {\n"
" (x * 100.0).round() / 100.0\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_magnitude() {\n"
" let p1 = Point::new(12, 13);\n"
" assert_eq!(round_two_digits(p1.magnitude()), 17.69);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_dist() {\n"
" let p1 = Point::new(10, 10);\n"
" let p2 = Point::new(14, 13);\n"
" assert_eq!(round_two_digits(p1.dist(p2)), 5.00);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_point_add() {\n"
" let p1 = Point::new(16, 16);\n"
" let p2 = p1 + Point::new(-4, 3);\n"
" assert_eq!(p2, Point::new(12, 19));\n"
" }\n"
"\n"
" #[test]\n"
" fn test_polygon_left_most_point() {\n"
" let p1 = Point::new(12, 13);\n"
" let p2 = Point::new(16, 16);\n"
"\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(p1);\n"
" poly.add_point(p2);\n"
" assert_eq!(poly.left_most_point(), Some(p1));\n"
" }\n"
"\n"
" #[test]\n"
" fn test_polygon_iter() {\n"
" let p1 = Point::new(12, 13);\n"
" let p2 = Point::new(16, 16);\n"
"\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(p1);\n"
" poly.add_point(p2);\n"
"\n"
" let points = poly.iter().cloned().collect::<Vec<_>>();\n"
" assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);\n"
" }\n"
"\n"
" #[test]\n"
" fn test_shape_perimeters() {\n"
" let mut poly = Polygon::new();\n"
" poly.add_point(Point::new(12, 13));\n"
" poly.add_point(Point::new(17, 11));\n"
" poly.add_point(Point::new(16, 16));\n"
" let shapes = vec![\n"
" Shape::from(poly),\n"
" Shape::from(Circle::new(Point::new(10, 20), 5)),\n"
" ];\n"
" let perimeters = shapes\n"
" .iter()\n"
" .map(Shape::perimeter)\n"
" .map(round_two_digits)\n"
" .collect::<Vec<_>>();\n"
" assert_eq!(perimeters, vec![15.48, 31.42]);\n"
" }\n"
"}\n"
"// ANCHOR_END: unit-tests\n"
"\n"
"fn main() {}\n"
"```"
msgstr ""
#: src/exercises/day-2/solutions-afternoon.md:1
msgid "Day 2 Afternoon Exercises"
msgstr "2일차 오후 연습문제"
#: src/exercises/day-2/solutions-afternoon.md:5
msgid "([back to exercise](luhn.md))"
msgstr ""
#: src/exercises/day-2/solutions-afternoon.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: luhn\n"
"pub fn luhn(cc_number: &str) -> bool {\n"
" // ANCHOR_END: luhn\n"
" let mut digits_seen = 0;\n"
" let mut sum = 0;\n"
" for (i, ch) in cc_number.chars().rev().filter(|&ch| ch != ' ')."
"enumerate() {\n"
" match ch.to_digit(10) {\n"
" Some(d) => {\n"
" sum += if i % 2 == 1 {\n"
" let dd = d * 2;\n"
" dd / 10 + dd % 10\n"
" } else {\n"
" d\n"
" };\n"
" digits_seen += 1;\n"
" }\n"
" None => return false,\n"
" }\n"
" }\n"
"\n"
" if digits_seen < 2 {\n"
" return false;\n"
" }\n"
"\n"
" sum % 10 == 0\n"
"}\n"
"\n"
"fn main() {\n"
" let cc_number = \"1234 5678 1234 5670\";\n"
" println!(\n"
" \"Is {cc_number} a valid credit card number? {}\",\n"
" if luhn(cc_number) { \"yes\" } else { \"no\" }\n"
" );\n"
"}\n"
"\n"
"// ANCHOR: unit-tests\n"
"#[test]\n"
"fn test_non_digit_cc_number() {\n"
" assert!(!luhn(\"foo\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_empty_cc_number() {\n"
" assert!(!luhn(\"\"));\n"
" assert!(!luhn(\" \"));\n"
" assert!(!luhn(\" \"));\n"
" assert!(!luhn(\" \"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_single_digit_cc_number() {\n"
" assert!(!luhn(\"0\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_two_digit_cc_number() {\n"
" assert!(luhn(\" 0 0 \"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_valid_cc_number() {\n"
" assert!(luhn(\"4263 9826 4026 9299\"));\n"
" assert!(luhn(\"4539 3195 0343 6467\"));\n"
" assert!(luhn(\"7992 7398 713\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_invalid_cc_number() {\n"
" assert!(!luhn(\"4223 9826 4026 9299\"));\n"
" assert!(!luhn(\"4539 3195 0343 6476\"));\n"
" assert!(!luhn(\"8273 1232 7352 0569\"));\n"
"}\n"
"// ANCHOR_END: unit-tests\n"
"```"
msgstr ""
#: src/exercises/day-2/solutions-afternoon.md:99
msgid "([back to exercise](strings-iterators.md))"
msgstr ""
#: src/exercises/day-2/solutions-afternoon.md:101
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: prefix_matches\n"
"pub fn prefix_matches(prefix: &str, request_path: &str) -> bool {\n"
" // ANCHOR_END: prefix_matches\n"
"\n"
" let mut request_segments = request_path.split('/');\n"
"\n"
" for prefix_segment in prefix.split('/') {\n"
" let Some(request_segment) = request_segments.next() else {\n"
" return false;\n"
" };\n"
" if request_segment != prefix_segment && prefix_segment != \"*\" {\n"
" return false;\n"
" }\n"
" }\n"
" true\n"
"\n"
" // Alternatively, Iterator::zip() lets us iterate simultaneously over "
"prefix\n"
" // and request segments. The zip() iterator is finished as soon as one "
"of\n"
" // the source iterators is finished, but we need to iterate over all "
"request\n"
" // segments. A neat trick that makes zip() work is to use map() and "
"chain()\n"
" // to produce an iterator that returns Some(str) for each pattern "
"segments,\n"
" // and then returns None indefinitely.\n"
"}\n"
"\n"
"// ANCHOR: unit-tests\n"
"#[test]\n"
"fn test_matches_without_wildcard() {\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers\"));\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/"
"abc-123\"));\n"
" assert!(prefix_matches(\"/v1/publishers\", \"/v1/publishers/abc/"
"books\"));\n"
"\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1\"));\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/publishersBooks\"));\n"
" assert!(!prefix_matches(\"/v1/publishers\", \"/v1/parent/"
"publishers\"));\n"
"}\n"
"\n"
"#[test]\n"
"fn test_matches_with_wildcard() {\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/books\"\n"
" ));\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/bar/books\"\n"
" ));\n"
" assert!(prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/books/book1\"\n"
" ));\n"
"\n"
" assert!(!prefix_matches(\"/v1/publishers/*/books\", \"/v1/"
"publishers\"));\n"
" assert!(!prefix_matches(\n"
" \"/v1/publishers/*/books\",\n"
" \"/v1/publishers/foo/booksByAuthor\"\n"
" ));\n"
"}\n"
"// ANCHOR_END: unit-tests\n"
"\n"
"fn main() {}\n"
"```"
msgstr ""
#: src/exercises/day-3/solutions-morning.md:1
msgid "Day 3 Morning Exercise"
msgstr "3일차 오전 연습문제"
#: src/exercises/day-3/solutions-morning.md:5
msgid "([back to exercise](simple-gui.md))"
msgstr ""
#: src/exercises/day-3/solutions-morning.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: setup\n"
"pub trait Widget {\n"
" /// Natural width of `self`.\n"
" fn width(&self) -> usize;\n"
"\n"
" /// Draw the widget into a buffer.\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write);\n"
"\n"
" /// Draw the widget on standard output.\n"
" fn draw(&self) {\n"
" let mut buffer = String::new();\n"
" self.draw_into(&mut buffer);\n"
" println!(\"{buffer}\");\n"
" }\n"
"}\n"
"\n"
"pub struct Label {\n"
" label: String,\n"
"}\n"
"\n"
"impl Label {\n"
" fn new(label: &str) -> Label {\n"
" Label {\n"
" label: label.to_owned(),\n"
" }\n"
" }\n"
"}\n"
"\n"
"pub struct Button {\n"
" label: Label,\n"
" callback: Box<dyn FnMut()>,\n"
"}\n"
"\n"
"impl Button {\n"
" fn new(label: &str, callback: Box<dyn FnMut()>) -> Button {\n"
" Button {\n"
" label: Label::new(label),\n"
" callback,\n"
" }\n"
" }\n"
"}\n"
"\n"
"pub struct Window {\n"
" title: String,\n"
" widgets: Vec<Box<dyn Widget>>,\n"
"}\n"
"\n"
"impl Window {\n"
" fn new(title: &str) -> Window {\n"
" Window {\n"
" title: title.to_owned(),\n"
" widgets: Vec::new(),\n"
" }\n"
" }\n"
"\n"
" fn add_widget(&mut self, widget: Box<dyn Widget>) {\n"
" self.widgets.push(widget);\n"
" }\n"
"\n"
" fn inner_width(&self) -> usize {\n"
" std::cmp::max(\n"
" self.title.chars().count(),\n"
" self.widgets.iter().map(|w| w.width()).max().unwrap_or(0),\n"
" )\n"
" }\n"
"}\n"
"\n"
"// ANCHOR_END: setup\n"
"\n"
"// ANCHOR: Window-width\n"
"impl Widget for Window {\n"
" fn width(&self) -> usize {\n"
" // ANCHOR_END: Window-width\n"
" // Add 4 paddings for borders\n"
" self.inner_width() + 4\n"
" }\n"
"\n"
" // ANCHOR: Window-draw_into\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" // ANCHOR_END: Window-draw_into\n"
" let mut inner = String::new();\n"
" for widget in &self.widgets {\n"
" widget.draw_into(&mut inner);\n"
" }\n"
"\n"
" let inner_width = self.inner_width();\n"
"\n"
" // TODO: after learning about error handling, you can change\n"
" // draw_into to return Result<(), std::fmt::Error>. Then use\n"
" // the ?-operator here instead of .unwrap().\n"
" writeln!(buffer, \"+-{:-<inner_width$}-+\", \"\").unwrap();\n"
" writeln!(buffer, \"| {:^inner_width$} |\", &self.title).unwrap();\n"
" writeln!(buffer, \"+={:=<inner_width$}=+\", \"\").unwrap();\n"
" for line in inner.lines() {\n"
" writeln!(buffer, \"| {:inner_width$} |\", line).unwrap();\n"
" }\n"
" writeln!(buffer, \"+-{:-<inner_width$}-+\", \"\").unwrap();\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Button-width\n"
"impl Widget for Button {\n"
" fn width(&self) -> usize {\n"
" // ANCHOR_END: Button-width\n"
" self.label.width() + 8 // add a bit of padding\n"
" }\n"
"\n"
" // ANCHOR: Button-draw_into\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" // ANCHOR_END: Button-draw_into\n"
" let width = self.width();\n"
" let mut label = String::new();\n"
" self.label.draw_into(&mut label);\n"
"\n"
" writeln!(buffer, \"+{:-<width$}+\", \"\").unwrap();\n"
" for line in label.lines() {\n"
" writeln!(buffer, \"|{:^width$}|\", &line).unwrap();\n"
" }\n"
" writeln!(buffer, \"+{:-<width$}+\", \"\").unwrap();\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Label-width\n"
"impl Widget for Label {\n"
" fn width(&self) -> usize {\n"
" // ANCHOR_END: Label-width\n"
" self.label\n"
" .lines()\n"
" .map(|line| line.chars().count())\n"
" .max()\n"
" .unwrap_or(0)\n"
" }\n"
"\n"
" // ANCHOR: Label-draw_into\n"
" fn draw_into(&self, buffer: &mut dyn std::fmt::Write) {\n"
" // ANCHOR_END: Label-draw_into\n"
" writeln!(buffer, \"{}\", &self.label).unwrap();\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: main\n"
"fn main() {\n"
" let mut window = Window::new(\"Rust GUI Demo 1.23\");\n"
" window.add_widget(Box::new(Label::new(\"This is a small text GUI demo."
"\")));\n"
" window.add_widget(Box::new(Button::new(\n"
" \"Click me!\",\n"
" Box::new(|| println!(\"You clicked the button!\")),\n"
" )));\n"
" window.draw();\n"
"}\n"
"// ANCHOR_END: main\n"
"```"
msgstr ""
#: src/exercises/day-3/solutions-afternoon.md:1
msgid "Day 3 Afternoon Exercises"
msgstr "3일차 오후 연습문제"
#: src/exercises/day-3/solutions-afternoon.md:5
msgid "([back to exercise](safe-ffi-wrapper.md))"
msgstr ""
#: src/exercises/day-3/solutions-afternoon.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: ffi\n"
"mod ffi {\n"
" use std::os::raw::{c_char, c_int};\n"
" #[cfg(not(target_os = \"macos\"))]\n"
" use std::os::raw::{c_long, c_ulong, c_ushort, c_uchar};\n"
"\n"
" // Opaque type. See https://doc.rust-lang.org/nomicon/ffi.html.\n"
" #[repr(C)]\n"
" pub struct DIR {\n"
" _data: [u8; 0],\n"
" _marker: core::marker::PhantomData<(*mut u8, core::marker::"
"PhantomPinned)>,\n"
" }\n"
"\n"
" // Layout according to the Linux man page for readdir(3), where ino_t "
"and\n"
" // off_t are resolved according to the definitions in\n"
" // /usr/include/x86_64-linux-gnu/{sys/types.h, bits/typesizes.h}.\n"
" #[cfg(not(target_os = \"macos\"))]\n"
" #[repr(C)]\n"
" pub struct dirent {\n"
" pub d_ino: c_ulong,\n"
" pub d_off: c_long,\n"
" pub d_reclen: c_ushort,\n"
" pub d_type: c_uchar,\n"
" pub d_name: [c_char; 256],\n"
" }\n"
"\n"
" // Layout according to the macOS man page for dir(5).\n"
" #[cfg(all(target_os = \"macos\"))]\n"
" #[repr(C)]\n"
" pub struct dirent {\n"
" pub d_fileno: u64,\n"
" pub d_seekoff: u64,\n"
" pub d_reclen: u16,\n"
" pub d_namlen: u16,\n"
" pub d_type: u8,\n"
" pub d_name: [c_char; 1024],\n"
" }\n"
"\n"
" extern \"C\" {\n"
" pub fn opendir(s: *const c_char) -> *mut DIR;\n"
"\n"
" #[cfg(not(all(target_os = \"macos\", target_arch = \"x86_64\")))]\n"
" pub fn readdir(s: *mut DIR) -> *const dirent;\n"
"\n"
" // See https://github.com/rust-lang/libc/issues/414 and the section "
"on\n"
" // _DARWIN_FEATURE_64_BIT_INODE in the macOS man page for stat(2).\n"
" //\n"
" // \"Platforms that existed before these updates were available\" "
"refers\n"
" // to macOS (as opposed to iOS / wearOS / etc.) on Intel and "
"PowerPC.\n"
" #[cfg(all(target_os = \"macos\", target_arch = \"x86_64\"))]\n"
" #[link_name = \"readdir$INODE64\"]\n"
" pub fn readdir(s: *mut DIR) -> *const dirent;\n"
"\n"
" pub fn closedir(s: *mut DIR) -> c_int;\n"
" }\n"
"}\n"
"\n"
"use std::ffi::{CStr, CString, OsStr, OsString};\n"
"use std::os::unix::ffi::OsStrExt;\n"
"\n"
"#[derive(Debug)]\n"
"struct DirectoryIterator {\n"
" path: CString,\n"
" dir: *mut ffi::DIR,\n"
"}\n"
"// ANCHOR_END: ffi\n"
"\n"
"// ANCHOR: DirectoryIterator\n"
"impl DirectoryIterator {\n"
" fn new(path: &str) -> Result<DirectoryIterator, String> {\n"
" // Call opendir and return a Ok value if that worked,\n"
" // otherwise return Err with a message.\n"
" // ANCHOR_END: DirectoryIterator\n"
" let path = CString::new(path).map_err(|err| format!(\"Invalid path: "
"{err}\"))?;\n"
" // SAFETY: path.as_ptr() cannot be NULL.\n"
" let dir = unsafe { ffi::opendir(path.as_ptr()) };\n"
" if dir.is_null() {\n"
" Err(format!(\"Could not open {:?}\", path))\n"
" } else {\n"
" Ok(DirectoryIterator { path, dir })\n"
" }\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Iterator\n"
"impl Iterator for DirectoryIterator {\n"
" type Item = OsString;\n"
" fn next(&mut self) -> Option<OsString> {\n"
" // Keep calling readdir until we get a NULL pointer back.\n"
" // ANCHOR_END: Iterator\n"
" // SAFETY: self.dir is never NULL.\n"
" let dirent = unsafe { ffi::readdir(self.dir) };\n"
" if dirent.is_null() {\n"
" // We have reached the end of the directory.\n"
" return None;\n"
" }\n"
" // SAFETY: dirent is not NULL and dirent.d_name is NUL\n"
" // terminated.\n"
" let d_name = unsafe { CStr::from_ptr((*dirent).d_name.as_ptr()) };\n"
" let os_str = OsStr::from_bytes(d_name.to_bytes());\n"
" Some(os_str.to_owned())\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: Drop\n"
"impl Drop for DirectoryIterator {\n"
" fn drop(&mut self) {\n"
" // Call closedir as needed.\n"
" // ANCHOR_END: Drop\n"
" if !self.dir.is_null() {\n"
" // SAFETY: self.dir is not NULL.\n"
" if unsafe { ffi::closedir(self.dir) } != 0 {\n"
" panic!(\"Could not close {:?}\", self.path);\n"
" }\n"
" }\n"
" }\n"
"}\n"
"\n"
"// ANCHOR: main\n"
"fn main() -> Result<(), String> {\n"
" let iter = DirectoryIterator::new(\".\")?;\n"
" println!(\"files: {:#?}\", iter.collect::<Vec<_>>());\n"
" Ok(())\n"
"}\n"
"// ANCHOR_END: main\n"
"\n"
"#[cfg(test)]\n"
"mod tests {\n"
" use super::*;\n"
" use std::error::Error;\n"
"\n"
" #[test]\n"
" fn test_nonexisting_directory() {\n"
" let iter = DirectoryIterator::new(\"no-such-directory\");\n"
" assert!(iter.is_err());\n"
" }\n"
"\n"
" #[test]\n"
" fn test_empty_directory() -> Result<(), Box<dyn Error>> {\n"
" let tmp = tempfile::TempDir::new()?;\n"
" let iter = DirectoryIterator::new(\n"
" tmp.path().to_str().ok_or(\"Non UTF-8 character in path\")?,\n"
" )?;\n"
" let mut entries = iter.collect::<Vec<_>>();\n"
" entries.sort();\n"
" assert_eq!(entries, &[\".\", \"..\"]);\n"
" Ok(())\n"
" }\n"
"\n"
" #[test]\n"
" fn test_nonempty_directory() -> Result<(), Box<dyn Error>> {\n"
" let tmp = tempfile::TempDir::new()?;\n"
" std::fs::write(tmp.path().join(\"foo.txt\"), \"The Foo "
"Diaries\\n\")?;\n"
" std::fs::write(tmp.path().join(\"bar.png\"), \"<PNG>\\n\")?;\n"
" std::fs::write(tmp.path().join(\"crab.rs\"), \"//! Crab\\n\")?;\n"
" let iter = DirectoryIterator::new(\n"
" tmp.path().to_str().ok_or(\"Non UTF-8 character in path\")?,\n"
" )?;\n"
" let mut entries = iter.collect::<Vec<_>>();\n"
" entries.sort();\n"
" assert_eq!(entries, &[\".\", \"..\", \"bar.png\", \"crab.rs\", \"foo."
"txt\"]);\n"
" Ok(())\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/solutions-morning.md:1
#, fuzzy
msgid "Bare Metal Rust Morning Exercise"
msgstr "Bare Metal Rust 오전 연습"
#: src/exercises/bare-metal/solutions-morning.md:5
msgid "([back to exercise](compass.md))"
msgstr ""
#: src/exercises/bare-metal/solutions-morning.md:7
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: top\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"extern crate panic_halt as _;\n"
"\n"
"use core::fmt::Write;\n"
"use cortex_m_rt::entry;\n"
"// ANCHOR_END: top\n"
"use core::cmp::{max, min};\n"
"use lsm303agr::{AccelOutputDataRate, Lsm303agr, MagOutputDataRate};\n"
"use microbit::display::blocking::Display;\n"
"use microbit::hal::prelude::*;\n"
"use microbit::hal::twim::Twim;\n"
"use microbit::hal::uarte::{Baudrate, Parity, Uarte};\n"
"use microbit::hal::Timer;\n"
"use microbit::pac::twim0::frequency::FREQUENCY_A;\n"
"use microbit::Board;\n"
"\n"
"const COMPASS_SCALE: i32 = 30000;\n"
"const ACCELEROMETER_SCALE: i32 = 700;\n"
"\n"
"// ANCHOR: main\n"
"#[entry]\n"
"fn main() -> ! {\n"
" let board = Board::take().unwrap();\n"
"\n"
" // Configure serial port.\n"
" let mut serial = Uarte::new(\n"
" board.UARTE0,\n"
" board.uart.into(),\n"
" Parity::EXCLUDED,\n"
" Baudrate::BAUD115200,\n"
" );\n"
"\n"
" // Set up the I2C controller and Inertial Measurement Unit.\n"
" // ANCHOR_END: main\n"
" writeln!(serial, \"Setting up IMU...\").unwrap();\n"
" let i2c = Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::"
"K100);\n"
" let mut imu = Lsm303agr::new_with_i2c(i2c);\n"
" imu.init().unwrap();\n"
" imu.set_mag_odr(MagOutputDataRate::Hz50).unwrap();\n"
" imu.set_accel_odr(AccelOutputDataRate::Hz50).unwrap();\n"
" let mut imu = imu.into_mag_continuous().ok().unwrap();\n"
"\n"
" // Set up display and timer.\n"
" let mut timer = Timer::new(board.TIMER0);\n"
" let mut display = Display::new(board.display_pins);\n"
"\n"
" let mut mode = Mode::Compass;\n"
" let mut button_pressed = false;\n"
"\n"
" // ANCHOR: loop\n"
" writeln!(serial, \"Ready.\").unwrap();\n"
"\n"
" loop {\n"
" // Read compass data and log it to the serial port.\n"
" // ANCHOR_END: loop\n"
" while !(imu.mag_status().unwrap().xyz_new_data\n"
" && imu.accel_status().unwrap().xyz_new_data)\n"
" {}\n"
" let compass_reading = imu.mag_data().unwrap();\n"
" let accelerometer_reading = imu.accel_data().unwrap();\n"
" writeln!(\n"
" serial,\n"
" \"{},{},{}\\t{},{},{}\",\n"
" compass_reading.x,\n"
" compass_reading.y,\n"
" compass_reading.z,\n"
" accelerometer_reading.x,\n"
" accelerometer_reading.y,\n"
" accelerometer_reading.z,\n"
" )\n"
" .unwrap();\n"
"\n"
" let mut image = [[0; 5]; 5];\n"
" let (x, y) = match mode {\n"
" Mode::Compass => (\n"
" scale(-compass_reading.x, -COMPASS_SCALE, COMPASS_SCALE, 0, "
"4) as usize,\n"
" scale(compass_reading.y, -COMPASS_SCALE, COMPASS_SCALE, 0, "
"4) as usize,\n"
" ),\n"
" Mode::Accelerometer => (\n"
" scale(\n"
" accelerometer_reading.x,\n"
" -ACCELEROMETER_SCALE,\n"
" ACCELEROMETER_SCALE,\n"
" 0,\n"
" 4,\n"
" ) as usize,\n"
" scale(\n"
" -accelerometer_reading.y,\n"
" -ACCELEROMETER_SCALE,\n"
" ACCELEROMETER_SCALE,\n"
" 0,\n"
" 4,\n"
" ) as usize,\n"
" ),\n"
" };\n"
" image[y][x] = 255;\n"
" display.show(&mut timer, image, 100);\n"
"\n"
" // If button A is pressed, switch to the next mode and briefly blink "
"all LEDs on.\n"
" if board.buttons.button_a.is_low().unwrap() {\n"
" if !button_pressed {\n"
" mode = mode.next();\n"
" display.show(&mut timer, [[255; 5]; 5], 200);\n"
" }\n"
" button_pressed = true;\n"
" } else {\n"
" button_pressed = false;\n"
" }\n"
" }\n"
"}\n"
"\n"
"#[derive(Copy, Clone, Debug, Eq, PartialEq)]\n"
"enum Mode {\n"
" Compass,\n"
" Accelerometer,\n"
"}\n"
"\n"
"impl Mode {\n"
" fn next(self) -> Self {\n"
" match self {\n"
" Self::Compass => Self::Accelerometer,\n"
" Self::Accelerometer => Self::Compass,\n"
" }\n"
" }\n"
"}\n"
"\n"
"fn scale(value: i32, min_in: i32, max_in: i32, min_out: i32, max_out: i32) -"
"> i32 {\n"
" let range_in = max_in - min_in;\n"
" let range_out = max_out - min_out;\n"
" cap(\n"
" min_out + range_out * (value - min_in) / range_in,\n"
" min_out,\n"
" max_out,\n"
" )\n"
"}\n"
"\n"
"fn cap(value: i32, min_value: i32, max_value: i32) -> i32 {\n"
" max(min_value, min(value, max_value))\n"
"}\n"
"```"
msgstr ""
#: src/exercises/bare-metal/solutions-afternoon.md:5
msgid "([back to exercise](rtc.md))"
msgstr ""
#: src/exercises/bare-metal/solutions-afternoon.md:7
msgid "`main.rs`:"
msgstr ""
#: src/exercises/bare-metal/solutions-afternoon.md:9
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: top\n"
"#![no_main]\n"
"#![no_std]\n"
"\n"
"mod exceptions;\n"
"mod logger;\n"
"mod pl011;\n"
"// ANCHOR_END: top\n"
"mod pl031;\n"
"\n"
"use crate::pl031::Rtc;\n"
"use arm_gic::gicv3::{IntId, Trigger};\n"
"use arm_gic::{irq_enable, wfi};\n"
"use chrono::{TimeZone, Utc};\n"
"use core::hint::spin_loop;\n"
"// ANCHOR: imports\n"
"use crate::pl011::Uart;\n"
"use arm_gic::gicv3::GicV3;\n"
"use core::panic::PanicInfo;\n"
"use log::{error, info, trace, LevelFilter};\n"
"use smccc::psci::system_off;\n"
"use smccc::Hvc;\n"
"\n"
"/// Base addresses of the GICv3.\n"
"const GICD_BASE_ADDRESS: *mut u64 = 0x800_0000 as _;\n"
"const GICR_BASE_ADDRESS: *mut u64 = 0x80A_0000 as _;\n"
"\n"
"/// Base address of the primary PL011 UART.\n"
"const PL011_BASE_ADDRESS: *mut u32 = 0x900_0000 as _;\n"
"// ANCHOR_END: imports\n"
"\n"
"/// Base address of the PL031 RTC.\n"
"const PL031_BASE_ADDRESS: *mut u32 = 0x901_0000 as _;\n"
"/// The IRQ used by the PL031 RTC.\n"
"const PL031_IRQ: IntId = IntId::spi(2);\n"
"\n"
"// ANCHOR: main\n"
"#[no_mangle]\n"
"extern \"C\" fn main(x0: u64, x1: u64, x2: u64, x3: u64) {\n"
" // Safe because `PL011_BASE_ADDRESS` is the base address of a PL011 "
"device,\n"
" // and nothing else accesses that address range.\n"
" let uart = unsafe { Uart::new(PL011_BASE_ADDRESS) };\n"
" logger::init(uart, LevelFilter::Trace).unwrap();\n"
"\n"
" info!(\"main({:#x}, {:#x}, {:#x}, {:#x})\", x0, x1, x2, x3);\n"
"\n"
" // Safe because `GICD_BASE_ADDRESS` and `GICR_BASE_ADDRESS` are the "
"base\n"
" // addresses of a GICv3 distributor and redistributor respectively, and\n"
" // nothing else accesses those address ranges.\n"
" let mut gic = unsafe { GicV3::new(GICD_BASE_ADDRESS, "
"GICR_BASE_ADDRESS) };\n"
" gic.setup();\n"
" // ANCHOR_END: main\n"
"\n"
" // Safe because `PL031_BASE_ADDRESS` is the base address of a PL031 "
"device,\n"
" // and nothing else accesses that address range.\n"
" let mut rtc = unsafe { Rtc::new(PL031_BASE_ADDRESS) };\n"
" let timestamp = rtc.read();\n"
" let time = Utc.timestamp_opt(timestamp.into(), 0).unwrap();\n"
" info!(\"RTC: {time}\");\n"
"\n"
" GicV3::set_priority_mask(0xff);\n"
" gic.set_interrupt_priority(PL031_IRQ, 0x80);\n"
" gic.set_trigger(PL031_IRQ, Trigger::Level);\n"
" irq_enable();\n"
" gic.enable_interrupt(PL031_IRQ, true);\n"
"\n"
" // Wait for 3 seconds, without interrupts.\n"
" let target = timestamp + 3;\n"
" rtc.set_match(target);\n"
" info!(\n"
" \"Waiting for {}\",\n"
" Utc.timestamp_opt(target.into(), 0).unwrap()\n"
" );\n"
" trace!(\n"
" \"matched={}, interrupt_pending={}\",\n"
" rtc.matched(),\n"
" rtc.interrupt_pending()\n"
" );\n"
" while !rtc.matched() {\n"
" spin_loop();\n"
" }\n"
" trace!(\n"
" \"matched={}, interrupt_pending={}\",\n"
" rtc.matched(),\n"
" rtc.interrupt_pending()\n"
" );\n"
" info!(\"Finished waiting\");\n"
"\n"
" // Wait another 3 seconds for an interrupt.\n"
" let target = timestamp + 6;\n"
" info!(\n"
" \"Waiting for {}\",\n"
" Utc.timestamp_opt(target.into(), 0).unwrap()\n"
" );\n"
" rtc.set_match(target);\n"
" rtc.clear_interrupt();\n"
" rtc.enable_interrupt(true);\n"
" trace!(\n"
" \"matched={}, interrupt_pending={}\",\n"
" rtc.matched(),\n"
" rtc.interrupt_pending()\n"
" );\n"
" while !rtc.interrupt_pending() {\n"
" wfi();\n"
" }\n"
" trace!(\n"
" \"matched={}, interrupt_pending={}\",\n"
" rtc.matched(),\n"
" rtc.interrupt_pending()\n"
" );\n"
" info!(\"Finished waiting\");\n"
"\n"
" // ANCHOR: main_end\n"
" system_off::<Hvc>().unwrap();\n"
"}\n"
"\n"
"#[panic_handler]\n"
"fn panic(info: &PanicInfo) -> ! {\n"
" error!(\"{info}\");\n"
" system_off::<Hvc>().unwrap();\n"
" loop {}\n"
"}\n"
"// ANCHOR_END: main_end\n"
"```"
msgstr ""
#: src/exercises/bare-metal/solutions-afternoon.md:149
msgid "`pl031.rs`:"
msgstr ""
#: src/exercises/bare-metal/solutions-afternoon.md:151
msgid ""
"```rust\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"use core::ptr::{addr_of, addr_of_mut};\n"
"\n"
"#[repr(C, align(4))]\n"
"struct Registers {\n"
" /// Data register\n"
" dr: u32,\n"
" /// Match register\n"
" mr: u32,\n"
" /// Load register\n"
" lr: u32,\n"
" /// Control register\n"
" cr: u8,\n"
" _reserved0: [u8; 3],\n"
" /// Interrupt Mask Set or Clear register\n"
" imsc: u8,\n"
" _reserved1: [u8; 3],\n"
" /// Raw Interrupt Status\n"
" ris: u8,\n"
" _reserved2: [u8; 3],\n"
" /// Masked Interrupt Status\n"
" mis: u8,\n"
" _reserved3: [u8; 3],\n"
" /// Interrupt Clear Register\n"
" icr: u8,\n"
" _reserved4: [u8; 3],\n"
"}\n"
"\n"
"/// Driver for a PL031 real-time clock.\n"
"#[derive(Debug)]\n"
"pub struct Rtc {\n"
" registers: *mut Registers,\n"
"}\n"
"\n"
"impl Rtc {\n"
" /// Constructs a new instance of the RTC driver for a PL031 device at "
"the\n"
" /// given base address.\n"
" ///\n"
" /// # Safety\n"
" ///\n"
" /// The given base address must point to the MMIO control registers of "
"a\n"
" /// PL031 device, which must be mapped into the address space of the "
"process\n"
" /// as device memory and not have any other aliases.\n"
" pub unsafe fn new(base_address: *mut u32) -> Self {\n"
" Self {\n"
" registers: base_address as *mut Registers,\n"
" }\n"
" }\n"
"\n"
" /// Reads the current RTC value.\n"
" pub fn read(&self) -> u32 {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL031 device which is appropriately mapped.\n"
" unsafe { addr_of!((*self.registers).dr).read_volatile() }\n"
" }\n"
"\n"
" /// Writes a match value. When the RTC value matches this then an "
"interrupt\n"
" /// will be generated (if it is enabled).\n"
" pub fn set_match(&mut self, value: u32) {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL031 device which is appropriately mapped.\n"
" unsafe { addr_of_mut!((*self.registers).mr).write_volatile(value) }\n"
" }\n"
"\n"
" /// Returns whether the match register matches the RTC value, whether or "
"not\n"
" /// the interrupt is enabled.\n"
" pub fn matched(&self) -> bool {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL031 device which is appropriately mapped.\n"
" let ris = unsafe { addr_of!((*self.registers).ris)."
"read_volatile() };\n"
" (ris & 0x01) != 0\n"
" }\n"
"\n"
" /// Returns whether there is currently an interrupt pending.\n"
" ///\n"
" /// This should be true if and only if `matched` returns true and the\n"
" /// interrupt is masked.\n"
" pub fn interrupt_pending(&self) -> bool {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL031 device which is appropriately mapped.\n"
" let ris = unsafe { addr_of!((*self.registers).mis)."
"read_volatile() };\n"
" (ris & 0x01) != 0\n"
" }\n"
"\n"
" /// Sets or clears the interrupt mask.\n"
" ///\n"
" /// When the mask is true the interrupt is enabled; when it is false "
"the\n"
" /// interrupt is disabled.\n"
" pub fn enable_interrupt(&mut self, mask: bool) {\n"
" let imsc = if mask { 0x01 } else { 0x00 };\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL031 device which is appropriately mapped.\n"
" unsafe { addr_of_mut!((*self.registers).imsc)."
"write_volatile(imsc) }\n"
" }\n"
"\n"
" /// Clears a pending interrupt, if any.\n"
" pub fn clear_interrupt(&mut self) {\n"
" // Safe because we know that self.registers points to the control\n"
" // registers of a PL031 device which is appropriately mapped.\n"
" unsafe { addr_of_mut!((*self.registers).icr).write_volatile(0x01) }\n"
" }\n"
"}\n"
"\n"
"// Safe because it just contains a pointer to device memory, which can be\n"
"// accessed from any context.\n"
"unsafe impl Send for Rtc {}\n"
"```"
msgstr ""
#: src/exercises/concurrency/solutions-morning.md:1
#, fuzzy
msgid "Concurrency Morning Exercise"
msgstr "3일차 오전 연습문제"
#: src/exercises/concurrency/solutions-morning.md:5
msgid "([back to exercise](dining-philosophers.md))"
msgstr ""
#: src/exercises/concurrency/solutions-morning.md:7
msgid ""
"```rust\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: Philosopher\n"
"use std::sync::{mpsc, Arc, Mutex};\n"
"use std::thread;\n"
"use std::time::Duration;\n"
"\n"
"struct Fork;\n"
"\n"
"struct Philosopher {\n"
" name: String,\n"
" // ANCHOR_END: Philosopher\n"
" left_fork: Arc<Mutex<Fork>>,\n"
" right_fork: Arc<Mutex<Fork>>,\n"
" thoughts: mpsc::SyncSender<String>,\n"
"}\n"
"\n"
"// ANCHOR: Philosopher-think\n"
"impl Philosopher {\n"
" fn think(&self) {\n"
" self.thoughts\n"
" .send(format!(\"Eureka! {} has a new idea!\", &self.name))\n"
" .unwrap();\n"
" }\n"
" // ANCHOR_END: Philosopher-think\n"
"\n"
" // ANCHOR: Philosopher-eat\n"
" fn eat(&self) {\n"
" // ANCHOR_END: Philosopher-eat\n"
" println!(\"{} is trying to eat\", &self.name);\n"
" let left = self.left_fork.lock().unwrap();\n"
" let right = self.right_fork.lock().unwrap();\n"
"\n"
" // ANCHOR: Philosopher-eat-end\n"
" println!(\"{} is eating...\", &self.name);\n"
" thread::sleep(Duration::from_millis(10));\n"
" }\n"
"}\n"
"\n"
"static PHILOSOPHERS: &[&str] =\n"
" &[\"Socrates\", \"Plato\", \"Aristotle\", \"Thales\", \"Pythagoras\"];\n"
"\n"
"fn main() {\n"
" // ANCHOR_END: Philosopher-eat-end\n"
" let (tx, rx) = mpsc::sync_channel(10);\n"
"\n"
" let forks = (0..PHILOSOPHERS.len())\n"
" .map(|_| Arc::new(Mutex::new(Fork)))\n"
" .collect::<Vec<_>>();\n"
"\n"
" for i in 0..forks.len() {\n"
" let tx = tx.clone();\n"
" let mut left_fork = Arc::clone(&forks[i]);\n"
" let mut right_fork = Arc::clone(&forks[(i + 1) % forks.len()]);\n"
"\n"
" // To avoid a deadlock, we have to break the symmetry\n"
" // somewhere. This will swap the forks without deinitializing\n"
" // either of them.\n"
" if i == forks.len() - 1 {\n"
" std::mem::swap(&mut left_fork, &mut right_fork);\n"
" }\n"
"\n"
" let philosopher = Philosopher {\n"
" name: PHILOSOPHERS[i].to_string(),\n"
" thoughts: tx,\n"
" left_fork,\n"
" right_fork,\n"
" };\n"
"\n"
" thread::spawn(move || {\n"
" for _ in 0..100 {\n"
" philosopher.eat();\n"
" philosopher.think();\n"
" }\n"
" });\n"
" }\n"
"\n"
" drop(tx);\n"
" for thought in rx {\n"
" println!(\"{thought}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/solutions-morning.md:104
#, fuzzy
msgid "Link Checker"
msgstr "멀티스레드 링크 검사기"
#: src/exercises/concurrency/solutions-morning.md:106
msgid "([back to exercise](link-checker.md))"
msgstr ""
#: src/exercises/concurrency/solutions-morning.md:108
msgid ""
"```rust,compile_fail\n"
"// Copyright 2022 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"use std::{sync::Arc, sync::Mutex, sync::mpsc, thread};\n"
"\n"
"// ANCHOR: setup\n"
"use reqwest::{blocking::Client, Url};\n"
"use scraper::{Html, Selector};\n"
"use thiserror::Error;\n"
"\n"
"#[derive(Error, Debug)]\n"
"enum Error {\n"
" #[error(\"request error: {0}\")]\n"
" ReqwestError(#[from] reqwest::Error),\n"
" #[error(\"bad http response: {0}\")]\n"
" BadResponse(String),\n"
"}\n"
"// ANCHOR_END: setup\n"
"\n"
"// ANCHOR: visit_page\n"
"#[derive(Debug)]\n"
"struct CrawlCommand {\n"
" url: Url,\n"
" extract_links: bool,\n"
"}\n"
"\n"
"fn visit_page(client: &Client, command: &CrawlCommand) -> Result<Vec<Url>, "
"Error> {\n"
" println!(\"Checking {:#}\", command.url);\n"
" let response = client.get(command.url.clone()).send()?;\n"
" if !response.status().is_success() {\n"
" return Err(Error::BadResponse(response.status().to_string()));\n"
" }\n"
"\n"
" let mut link_urls = Vec::new();\n"
" if !command.extract_links {\n"
" return Ok(link_urls);\n"
" }\n"
"\n"
" let base_url = response.url().to_owned();\n"
" let body_text = response.text()?;\n"
" let document = Html::parse_document(&body_text);\n"
"\n"
" let selector = Selector::parse(\"a\").unwrap();\n"
" let href_values = document\n"
" .select(&selector)\n"
" .filter_map(|element| element.value().attr(\"href\"));\n"
" for href in href_values {\n"
" match base_url.join(href) {\n"
" Ok(link_url) => {\n"
" link_urls.push(link_url);\n"
" }\n"
" Err(err) => {\n"
" println!(\"On {base_url:#}: ignored unparsable {href:?}: "
"{err}\");\n"
" }\n"
" }\n"
" }\n"
" Ok(link_urls)\n"
"}\n"
"// ANCHOR_END: visit_page\n"
"\n"
"struct CrawlState {\n"
" domain: String,\n"
" visited_pages: std::collections::HashSet<String>,\n"
"}\n"
"\n"
"impl CrawlState {\n"
" fn new(start_url: &Url) -> CrawlState {\n"
" let mut visited_pages = std::collections::HashSet::new();\n"
" visited_pages.insert(start_url.as_str().to_string());\n"
" CrawlState {\n"
" domain: start_url.domain().unwrap().to_string(),\n"
" visited_pages,\n"
" }\n"
" }\n"
"\n"
" /// Determine whether links within the given page should be extracted.\n"
" fn should_extract_links(&self, url: &Url) -> bool {\n"
" let Some(url_domain) = url.domain() else {\n"
" return false;\n"
" };\n"
" url_domain == self.domain\n"
" }\n"
"\n"
" /// Mark the given page as visited, returning true if it had already\n"
" /// been visited.\n"
" fn mark_visited(&mut self, url: &Url) -> bool {\n"
" self.visited_pages.insert(url.as_str().to_string())\n"
" }\n"
"}\n"
"\n"
"type CrawlResult = Result<Vec<Url>, (Url, Error)>;\n"
"fn spawn_crawler_threads(\n"
" command_receiver: mpsc::Receiver<CrawlCommand>,\n"
" result_sender: mpsc::Sender<CrawlResult>,\n"
" thread_count: u32,\n"
") {\n"
" let command_receiver = Arc::new(Mutex::new(command_receiver));\n"
"\n"
" for _ in 0..thread_count {\n"
" let result_sender = result_sender.clone();\n"
" let command_receiver = command_receiver.clone();\n"
" thread::spawn(move || {\n"
" let client = Client::new();\n"
" loop {\n"
" let command_result = {\n"
" let receiver_guard = command_receiver.lock().unwrap();\n"
" receiver_guard.recv()\n"
" };\n"
" let Ok(crawl_command) = command_result else {\n"
" // The sender got dropped. No more commands coming in.\n"
" break;\n"
" };\n"
" let crawl_result = match visit_page(&client, &crawl_command) "
"{\n"
" Ok(link_urls) => Ok(link_urls),\n"
" Err(error) => Err((crawl_command.url, error)),\n"
" };\n"
" result_sender.send(crawl_result).unwrap();\n"
" }\n"
" });\n"
" }\n"
"}\n"
"\n"
"fn control_crawl(\n"
" start_url: Url,\n"
" command_sender: mpsc::Sender<CrawlCommand>,\n"
" result_receiver: mpsc::Receiver<CrawlResult>,\n"
") -> Vec<Url> {\n"
" let mut crawl_state = CrawlState::new(&start_url);\n"
" let start_command = CrawlCommand { url: start_url, extract_links: "
"true };\n"
" command_sender.send(start_command).unwrap();\n"
" let mut pending_urls = 1;\n"
"\n"
" let mut bad_urls = Vec::new();\n"
" while pending_urls > 0 {\n"
" let crawl_result = result_receiver.recv().unwrap();\n"
" pending_urls -= 1;\n"
"\n"
" match crawl_result {\n"
" Ok(link_urls) => {\n"
" for url in link_urls {\n"
" if crawl_state.mark_visited(&url) {\n"
" let extract_links = crawl_state."
"should_extract_links(&url);\n"
" let crawl_command = CrawlCommand { url, "
"extract_links };\n"
" command_sender.send(crawl_command).unwrap();\n"
" pending_urls += 1;\n"
" }\n"
" }\n"
" }\n"
" Err((url, error)) => {\n"
" bad_urls.push(url);\n"
" println!(\"Got crawling error: {:#}\", error);\n"
" continue;\n"
" }\n"
" }\n"
" }\n"
" bad_urls\n"
"}\n"
"\n"
"fn check_links(start_url: Url) -> Vec<Url> {\n"
" let (result_sender, result_receiver) = mpsc::channel::<CrawlResult>();\n"
" let (command_sender, command_receiver) = mpsc::channel::"
"<CrawlCommand>();\n"
" spawn_crawler_threads(command_receiver, result_sender, 16);\n"
" control_crawl(start_url, command_sender, result_receiver)\n"
"}\n"
"\n"
"fn main() {\n"
" let start_url = reqwest::Url::parse(\"https://www.google.org\")."
"unwrap();\n"
" let bad_urls = check_links(start_url);\n"
" println!(\"Bad URLs: {:#?}\", bad_urls);\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/solutions-afternoon.md:1
#, fuzzy
msgid "Concurrency Afternoon Exercise"
msgstr "1일차 오후 연습문제"
#: src/exercises/concurrency/solutions-afternoon.md:5
msgid "([back to exercise](dining-philosophers-async.md))"
msgstr ""
#: src/exercises/concurrency/solutions-afternoon.md:7
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: Philosopher\n"
"use std::sync::Arc;\n"
"use tokio::time;\n"
"use tokio::sync::mpsc::{self, Sender};\n"
"use tokio::sync::Mutex;\n"
"\n"
"struct Fork;\n"
"\n"
"struct Philosopher {\n"
" name: String,\n"
" // ANCHOR_END: Philosopher\n"
" left_fork: Arc<Mutex<Fork>>,\n"
" right_fork: Arc<Mutex<Fork>>,\n"
" thoughts: Sender<String>,\n"
"}\n"
"\n"
"// ANCHOR: Philosopher-think\n"
"impl Philosopher {\n"
" async fn think(&self) {\n"
" self.thoughts\n"
" .send(format!(\"Eureka! {} has a new idea!\", &self.name))."
"await\n"
" .unwrap();\n"
" }\n"
" // ANCHOR_END: Philosopher-think\n"
"\n"
" // ANCHOR: Philosopher-eat\n"
" async fn eat(&self) {\n"
" // Pick up forks...\n"
" // ANCHOR_END: Philosopher-eat\n"
" let _first_lock = self.left_fork.lock().await;\n"
" // Add a delay before picking the second fork to allow the "
"execution\n"
" // to transfer to another task\n"
" time::sleep(time::Duration::from_millis(1)).await;\n"
" let _second_lock = self.right_fork.lock().await;\n"
"\n"
" // ANCHOR: Philosopher-eat-body\n"
" println!(\"{} is eating...\", &self.name);\n"
" time::sleep(time::Duration::from_millis(5)).await;\n"
" // ANCHOR_END: Philosopher-eat-body\n"
"\n"
" // The locks are dropped here\n"
" // ANCHOR: Philosopher-eat-end\n"
" }\n"
"}\n"
"\n"
"static PHILOSOPHERS: &[&str] =\n"
" &[\"Socrates\", \"Plato\", \"Aristotle\", \"Thales\", \"Pythagoras\"];\n"
"\n"
"#[tokio::main]\n"
"async fn main() {\n"
" // ANCHOR_END: Philosopher-eat-end\n"
" // Create forks\n"
" let mut forks = vec![];\n"
" (0..PHILOSOPHERS.len()).for_each(|_| forks.push(Arc::new(Mutex::"
"new(Fork))));\n"
"\n"
" // Create philosophers\n"
" let (philosophers, mut rx) = {\n"
" let mut philosophers = vec![];\n"
" let (tx, rx) = mpsc::channel(10);\n"
" for (i, name) in PHILOSOPHERS.iter().enumerate() {\n"
" let left_fork = Arc::clone(&forks[i]);\n"
" let right_fork = Arc::clone(&forks[(i + 1) % PHILOSOPHERS."
"len()]);\n"
" // To avoid a deadlock, we have to break the symmetry\n"
" // somewhere. This will swap the forks without deinitializing\n"
" // either of them.\n"
" if i == 0 {\n"
" std::mem::swap(&mut left_fork, &mut right_fork);\n"
" }\n"
" philosophers.push(Philosopher {\n"
" name: name.to_string(),\n"
" left_fork,\n"
" right_fork,\n"
" thoughts: tx.clone(),\n"
" });\n"
" }\n"
" (philosophers, rx)\n"
" // tx is dropped here, so we don't need to explicitly drop it later\n"
" };\n"
"\n"
" // Make them think and eat\n"
" for phil in philosophers {\n"
" tokio::spawn(async move {\n"
" for _ in 0..100 {\n"
" phil.think().await;\n"
" phil.eat().await;\n"
" }\n"
" });\n"
"\n"
" }\n"
"\n"
" // Output their thoughts\n"
" while let Some(thought) = rx.recv().await {\n"
" println!(\"Here is a thought: {thought}\");\n"
" }\n"
"}\n"
"```"
msgstr ""
#: src/exercises/concurrency/solutions-afternoon.md:121
msgid "([back to exercise](chat-app.md))"
msgstr ""
#: src/exercises/concurrency/solutions-afternoon.md:125
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: setup\n"
"use futures_util::sink::SinkExt;\n"
"use std::error::Error;\n"
"use std::net::SocketAddr;\n"
"use tokio::net::{TcpListener, TcpStream};\n"
"use tokio::sync::broadcast::{channel, Sender};\n"
"use tokio_websockets::{Message, ServerBuilder, WebsocketStream};\n"
"// ANCHOR_END: setup\n"
"\n"
"// ANCHOR: handle_connection\n"
"async fn handle_connection(\n"
" addr: SocketAddr,\n"
" mut ws_stream: WebsocketStream<TcpStream>,\n"
" bcast_tx: Sender<String>,\n"
") -> Result<(), Box<dyn Error + Send + Sync>> {\n"
" // ANCHOR_END: handle_connection\n"
"\n"
" ws_stream\n"
" .send(Message::text(\"Welcome to chat! Type a message\".into()))\n"
" .await?;\n"
" let mut bcast_rx = bcast_tx.subscribe();\n"
"\n"
" // A continuous loop for concurrently performing two tasks: (1) "
"receiving\n"
" // messages from `ws_stream` and broadcasting them, and (2) receiving\n"
" // messages on `bcast_rx` and sending them to the client.\n"
" loop {\n"
" tokio::select! {\n"
" incoming = ws_stream.next() => {\n"
" match incoming {\n"
" Some(Ok(msg)) => {\n"
" let msg = msg.as_text()?;\n"
" println!(\"From client {addr:?} {msg:?}\");\n"
" bcast_tx.send(msg.into())?;\n"
" }\n"
" Some(Err(err)) => return Err(err.into()),\n"
" None => return Ok(()),\n"
" }\n"
" }\n"
" msg = bcast_rx.recv() => {\n"
" ws_stream.send(Message::text(msg?)).await?;\n"
" }\n"
" }\n"
" }\n"
" // ANCHOR: main\n"
"}\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {\n"
" let (bcast_tx, _) = channel(16);\n"
"\n"
" let listener = TcpListener::bind(\"127.0.0.1:2000\").await?;\n"
" println!(\"listening on port 2000\");\n"
"\n"
" loop {\n"
" let (socket, addr) = listener.accept().await?;\n"
" println!(\"New connection from {addr:?}\");\n"
" let bcast_tx = bcast_tx.clone();\n"
" tokio::spawn(async move {\n"
" // Wrap the raw TCP stream into a websocket.\n"
" let ws_stream = ServerBuilder::new().accept(socket).await?;\n"
"\n"
" handle_connection(addr, ws_stream, bcast_tx).await\n"
" });\n"
" }\n"
"}\n"
"// ANCHOR_END: main\n"
"```"
msgstr ""
#: src/exercises/concurrency/solutions-afternoon.md:210
msgid ""
"```rust,compile_fail\n"
"// Copyright 2023 Google LLC\n"
"//\n"
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n"
"// you may not use this file except in compliance with the License.\n"
"// You may obtain a copy of the License at\n"
"//\n"
"// http://www.apache.org/licenses/LICENSE-2.0\n"
"//\n"
"// Unless required by applicable law or agreed to in writing, software\n"
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n"
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
"// See the License for the specific language governing permissions and\n"
"// limitations under the License.\n"
"\n"
"// ANCHOR: setup\n"
"use futures_util::SinkExt;\n"
"use http::Uri;\n"
"use tokio::io::{AsyncBufReadExt, BufReader};\n"
"use tokio_websockets::{ClientBuilder, Message};\n"
"\n"
"#[tokio::main]\n"
"async fn main() -> Result<(), tokio_websockets::Error> {\n"
" let mut ws_stream = ClientBuilder::from_uri(Uri::"
"from_static(\"ws://127.0.0.1:2000\"))\n"
" .connect()\n"
" .await?;\n"
"\n"
" let stdin = tokio::io::stdin();\n"
" let mut stdin = BufReader::new(stdin).lines();\n"
"\n"
" // ANCHOR_END: setup\n"
" // Continuous loop for concurrently sending and receiving messages.\n"
" loop {\n"
" tokio::select! {\n"
" incoming = ws_stream.next() => {\n"
" match incoming {\n"
" Some(Ok(msg)) => println!(\"From server: {}\", msg."
"as_text()?),\n"
" Some(Err(err)) => return Err(err.into()),\n"
" None => return Ok(()),\n"
" }\n"
" }\n"
" res = stdin.next_line() => {\n"
" match res {\n"
" Ok(None) => return Ok(()),\n"
" Ok(Some(line)) => ws_stream.send(Message::text(line."
"to_string())).await?,\n"
" Err(err) => return Err(err.into()),\n"
" }\n"
" }\n"
"\n"
" }\n"
" }\n"
"}\n"
"```"
msgstr ""