<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>h_channni.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요:)</description>
        <lastBuildDate>Fri, 18 Jul 2025 15:22:09 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>h_channni.log</title>
            <url>https://velog.velcdn.com/images/h_channni/profile/dfdfb1a6-89a9-4150-a87c-8c5eeff7e3e8/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. h_channni.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/h_channni" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Paper Review : Safeguarding Mobile GUI Agent via Logic-based Action Verification (VeriSafe Agent)]]></title>
            <link>https://velog.io/@h_channni/Paper-Review-Safeguarding-Mobile-GUI-Agent-via-Logic-based-Action-Verification-VeriSafe-Agent</link>
            <guid>https://velog.io/@h_channni/Paper-Review-Safeguarding-Mobile-GUI-Agent-via-Logic-based-Action-Verification-VeriSafe-Agent</guid>
            <pubDate>Fri, 18 Jul 2025 15:22:09 GMT</pubDate>
            <description><![CDATA[<p>링크: 
<a href="https://arxiv.org/abs/2503.18492">https://arxiv.org/abs/2503.18492</a></p>
<h2 id="introduction">Introduction</h2>
<hr>
<p>대규모 파운데이션 모델들 (LFMs, ChatGPT나 Gemini 등을 생각하면 되겠다) 이 눈부신 발전을 함에 따라, 이를 모바일 GUI와 상호작용하는 데 활용해서 모바일 작업들을 자동화하려는 <strong><em>‘Mobile GUI Agents’</em></strong>와 관련한 연구들이 등장하고 있다.</p>
<p>최근 Mobile GUI Agents 관련 연구들은 LFM을 활용해 자연어로 들어오는 user request를 해석하고, 이를 모바일 상에서의 UI interaction으로 ‘번역’하는 식으로 LFM의 자연어 처리 능력과 추론 능력을 활용하고 있다.</p>
<p>다만, 아무리 LFM이 발전했다 하더라도, 이를 기반으로 하는 Mobile GUI Agents에게는 근본적인 한계점이 있다: 바로 <strong>LFM의 근본적인 확률적인 특성</strong>으로 인해, 모바일 작업 자동화를 실제 애플리케이션에 적용하기에는 <strong>안전성, 신뢰성 이슈</strong>가 대두될 수밖에 없는 현실이다. 특히, 모바일 앱 상호작용이라는 것은 매우 모호하고, 맥락에 의존적이어서 많은 성능 향상이 이루어진 최근의 SOTA LFM들에게도 여전히 어려운 작업이다.</p>
<p>또 하나 중요한 문제는 mobile task들의 특성이다. 특히 <strong>비가역적이면서도 LFM이 만들어내는 에러가 정말 심각한 결과를 초래하는 경우</strong>가 많다는 것이다. 금융 거래나 메신저 등의 예시를 생각할 수 있는데, 이런 task들은 한 번 잘못 실행이 되어버리면 되돌릴 수 없다는 특성이 있다. 이런 작업들에서까지 Mobile GUI Agents를 활용하려면 그 전에 <strong><em>견고한 safeguard와 검증 메커니즘</em></strong>을 확보하는 것이 필수적이다.</p>
<h2 id="prior-works">Prior works</h2>
<hr>
<p>그렇다면, 기존의 연구들에서는 Mobile GUI Agents의 행동을 어떻게 ‘검증’을 시도했을까?</p>
<p><strong><em>Reflection 기법</em></strong>이 대표적이다.</p>
<p>이는 primary GUI agent가 생성한 행동을 리뷰하기 위해 또 다른 LFM을 활용한 <em>reflection agents</em>를 두는 multi-agent 방식의 접근법이다.</p>
<p>Reflection 기반 기법은 크게 두 가지로 분류할 수 있는데, pre-action 검증과 post-action 검증이 있다:</p>
<ul>
<li><strong><em>pre-action 검증</em></strong>은 특정 행동이 모바일 앱에서 <strong>실행되기 ‘전에’</strong> 검증하는 기법이다. 앞서 말했던 금융 거래와 같은 비가역적인 행동을 검증하기 위해서는 pre-action 검증이 실행되어야 하겠다.
하지만, 이 방법은 행동의 결과를 <strong>‘예측’</strong>해야 한다는 어려움이 있고, 따라서 검증 정확도가 떨어진다는 문제가 있다.</li>
<li><strong><em>post-action 검증</em></strong>은 특정 행동이 <strong>실행된 ‘이후’</strong> 그 결과인 애플리케이션 상태를 보고 올바른 행동인지 검증하는 기법이다. 
이를 통해 검증 정확도를 크게 향상시킬 수 있었다. 다만, 앞서 말했던 비가역적인 action을 사전에 막을 수 없다는 치명적인 한계가 존재한다.</li>
</ul>
<p>또한, Reflection은 본질적으로 LFM을 사용해서 검증이 이루어지는 것이기 때문에, 정확도를 높일 수는 있더라도 결국 이 방식으로는 AI의 확률적인 특성에서 벗어날 수 없다는 것도 이 기법의 한계점이다. </p>
<h2 id="verisafe-agent-vsa">VeriSafe Agent (VSA)</h2>
<hr>
<p>앞서 말했던 기존 연구인 Reflection 기법의 한계를 보완하기 위해 이 논문에서는 <strong><em>VeriSafe Agent(VSA)</em></strong>를 제안한다.</p>
<p>이 Agent는 확률적인 추론 대신, <strong>논리 기반의 신뢰성 있는 pre-action 검증</strong>을 제공한다.
<img src="https://velog.velcdn.com/images/h_channni/post/c2833981-9529-4994-9bc7-35e8860c95cf/image.png" alt=""></p>
<p>위 Figure의 우측을 보면, GUI agent의 UI action을 pre-action 단계에서 intercept하여, User Instruction과 Application State를 논리적인 formula로 형식화하여 올바른 action인지 검증을 수행한다.</p>
<p>즉, VSA는 사람이 natural language로 내리는 지시사항을 formal specification으로 자동 번역하는 <strong><em>Autoformalization</em></strong>이라는 concept을 활용한다.</p>
<p>또한, Figure를 보면 알 수 있듯이 VSA는 직접 행동을 수행하는 Mobile GUI Agent의 새로운 종류가 아니라, <strong>기존 agent를 ‘검증’해 주는 시스템</strong>이다.</p>
<h3 id="system-workflow">System Workflow</h3>
<p>VSA의 system workflow는 아래 4가지 단계이다 :</p>
<ul>
<li><strong>App Development Phase</strong></li>
<li><strong>Intent Encoding</strong></li>
<li><strong>Verification</strong></li>
<li><strong>Feedback Generation</strong></li>
</ul>
<p>먼저, <strong>App Development Phase</strong>에서는 VSA를 위해 사전에 진행되어야 하는 단계로, 개발자가 직접 모바일 애플리케이션을 개발할 때 Predicates과 State transitions를 정의해 줘야 한다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/5ffde0a8-0ee2-47b4-a007-8199c19427ae/image.png" alt=""></p>
<p><strong>Intent Encoding 단계</strong>에서는 위 그림처럼 유저가 자연어로 내리는 지시사항을 구조화된 logical rules로 변환해 주는 작업이 실행된다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/097da0cf-0f93-4e5c-9e46-9d87fbe4bacf/image.png" alt=""></p>
<p><strong>Verification 단계</strong>에서는 기존 GUI Agent가 유저의 지시사항을 받고 실행한 UI Action에 대한 검증이 이루어지게 된다. </p>
<p>사전에 개발자가 개발해 둔 VSA developer library를 기반으로 해당 action을 수행했을 때 예상되는 state transition이 도출된다. Intent Verifier는 이 결과를 기반으로 logical rules에 따라 적절한 action인지를 검증하는 단계를 거친다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/1f815a05-509d-4241-8695-ee19a6acc420/image.png" alt=""></p>
<p>마지막으로 <strong>Feedback Generation 단계</strong>에서는 앞선 검증 단계에서의 검증이 성공했는지, 실패했는지에 따라 VSA가 GUI Agent에게 적절한 피드백을 제공하게 되는 단계이다.</p>
<h3 id="challenges">Challenges</h3>
<p>논문에서는 VSA가 다루는 3가지 key challenges를 제시한다 : </p>
<ul>
<li><strong>C1. How to formally express the user’s intent and the app’s execution flow in logically tractable representation?</strong></li>
<li><strong>C2. How to accurately translate natural language user instructions into a formal representation and perform runtime verification against it?</strong></li>
<li><strong>C3. How to effectively communicate verification results back to the GUI agent in an actionable, explainable manner?</strong></li>
</ul>
<p>이 각각의 challenges에 대해서 VSA는 각각의 solutions들을 매핑해서 보여주는데, </p>
<ul>
<li><strong>C1</strong>에 대해서는 <strong>domain-specific language(DSL)</strong> 과 함께 관련된 <strong>developer library</strong>를 제시한다. <strong>(S1)</strong></li>
<li><strong>C2</strong>에 대해서는 <strong>self-corrective encoding approach</strong>(in Intent Encoder)와 <strong>two-tiered verification strategy</strong>(in Intent Verifier)를 제시한다. <strong>(S2)</strong></li>
<li><strong>C3</strong>에 대해서는 구조화된 <strong>feedback generation mechanism</strong>을 제시한다. <strong>(S3)</strong></li>
</ul>
<p>이 각각의 solution들을 하나하나 자세히 알아보도록 하자.</p>
<h2 id="domain-specific-language-dsl---for-solution-1">Domain-Specific Language (DSL) - for Solution 1</h2>
<hr>
<p>DSL은 특정 도메인에 특화된 computer language이다. 아래 위키백과 링크에서 더 자세한 내용을 확인할 수 있다.</p>
<p><a href="https://en.wikipedia.org/wiki/Domain-specific_language">https://en.wikipedia.org/wiki/Domain-specific_language</a></p>
<p>이 논문에서는 유저가 natural language로 내리는 instruction에 포함되어 있는 모바일 애플리케이션에서의 제약조건 / 실행 흐름 / 조건부 분기 등을 유연하게 표현하기 위해 DSL을 새롭게 설계한다.</p>
<h3 id="design-of-domain-specific-language">Design of Domain-Specific Language</h3>
<p><img src="https://velog.velcdn.com/images/h_channni/post/6c944230-44b8-4790-a480-132e160b9d2f/image.png" alt=""></p>
<p>위 장표는 DSL의 구조를 시각화해 본 그래프이다. </p>
<p>유저의 지시사항 하나를 <em>Specification</em>이라 한다. 이것은 여러 가지의 <em>Rule</em>들로 구성되어 있다.</p>
<p><em>Rule*은 *Predicate</em>(전제조건)들과 <em>Objective</em>(결론)으로, 다시 <em>Predicate</em>은 또 <em>State Predicate</em>들로 .. 이런 식으로 각각을 구성하는 요소들로 쪼개 나간다는 것을 알 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/2eb0e534-b63a-4805-94e6-27c66bfd4a3c/image.png" alt=""></p>
<p>Figure 2와 Figure 3에서 DSL의 syntax와 이를 활용한 instruction의 <em>Specification</em>을 확인할 수 있다.</p>
<p>각 <em>Rule*은 하나의 Horn Cluase로 표현되고, 하나의 user instruction(i.e. *Specification</em>)을 여러 개의 <em>Rule</em>들로  쪼개서 표현하는 역할을 한다. </p>
<p>이 <em>Rule</em>은 또 전제조건에 해당하는 <em>State Predicates</em>들과 결론에 해당하는 <em>Objective</em>로 구성된다.</p>
<p>Figure 3의 예시를 보면 직관적으로 이해가 가능할 것이다. “R이라는 이름의 레스토랑에 19시 전으로 예약을 하고, 해당 시간대에 레스토랑이 이용 불가능하다면, 아무것도 하지 말아라” 라는 유저의 지시사항을 3개의 Rule로 표현하였다:</p>
<blockquote>
</blockquote>
<p>R1 : 레스토랑의 정보 (이름이 ‘R’인지) 와 예약 정보 (날짜가 오늘인지, 시간이 19시 이전인지, 예약이 가능한지) 가 true이면 → Reserve를 진행한다.
R2 : Reserve가 수행되고, 예약 결과가 성공이면 → Done(즉, action 마침)
R3 : 만약 해당 시간에 예약이 불가능하면 (예약 정보에서 available 속성이 false) → Done (즉, 예약하지 않고 action을 마침)</p>
<blockquote>
</blockquote>
<p>R1의 결론이 R2의 전제조건으로 쓰이는 것과 같은 예시로 DSL이 action의 선행관계를 표현해 낸다는 것을 알 수 있다.</p>
<p>이와 같은 DSL을 구조화하여, VSA는 자연어로 된 유저의 지시사항을 형식적인 표현으로 ‘번역’을 성공적으로 수행할 수 있다.</p>
<h3 id="developer-library">Developer Library</h3>
<p>이렇게 개념적으로 구현한 DSL을 실제 모바일 어플리케이션과 Mobile GUI Agents의 행동을 검증하고 평가하는 데 활용하기 위해서는 개발자가 앱의 상태(<em>state predicates</em>), 그리고 그와 관련된 <em>state transitions</em>를 ‘직접’ 정의해 줘야 한다. </p>
<p>개발자가 앱의 모든 상태와 상태 전이를 추가적으로 정의해줘야 한다는 것은 개발자에게 부담이 될 수도 있겠지만, 이미 React Native, iOS’s SwiftUI 등의 프레임워크에서 앱의 state와 transition 관리라는 개념이 존재하는 만큼 이것과 align함으로써 개발자의 부담이 그렇게 크지 않다고 말한다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/2211fb9a-f8a3-43f8-989a-351ec98f39fc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/5dd6de4b-d298-4934-91ea-91efa87da9af/image.png" alt=""></p>
<p>위 그림들과 같이 앱의 상태 정보와 상태 업데이트 정보를 몇 줄의 추가적인 코드 작성으로 쉽게 추가할 수 있는 개발자 라이브러리를 제공한다.</p>
<h2 id="verification-engine---for-solution-2">Verification Engine - for Solution 2</h2>
<hr>
<p>유저의 지시사항을 앞서 정의한 논리적 표현으로 인코딩하고, 이를 런타임에 정확하게 검증하기 위해서 VSA는 Intent Encoder와 Intent Verifier를 내부 엔진으로 구축한다. </p>
<p>더 자세한 방법론에 대해 알아보자.</p>
<h3 id="intent-encoder-self-corrective-encoding">Intent Encoder (self-corrective encoding)</h3>
<p>Intent Encoder를 구현할 때 LFM에만 의존하게 되면, 할루시네이션의 발생 가능성을 생각하지 않을 수 없다.</p>
<p>이 리스크를 완화하기 위해서, 논문에서는 <strong><em>self-corrective encoding</em></strong>이라는 기법을 적용한다. 이는 아래의 두 가지 단계로 구성된다.</p>
<ol>
<li><strong><em>Rule-based Syntax Checking</em></strong> : 이 단계에서는 Encoder LLM이 natural language 유저 지시사항을 보고 생성한 <em>Specifications</em>를 검사한다. 앞서 정의한 DSL의 문법을 철저히 지키는지를 검사하게 된다.</li>
<li><strong><em>Decoding-based Semantics Checking :</em></strong> 이 단계에서는 Decoder LLM과 Checker LLM을 활용해 생성한 <em>Specifications</em>을 다시 natural language로 디코딩하고, 이를 기존 유저 지시사항과 비교하면서 Semantic 정보를 확인한다. </li>
</ol>
<p>이렇게 syntax와 semantic을 확인하는 두 단계의 과정을 거치면서, Intent Encoder는 user instruction이 DSL Specification으로 정확하게 인코딩한다.</p>
<h3 id="intent-verifier-two-levels-of-verification">Intent Verifier (two levels of verification)</h3>
<p>인코딩을 마치게 되면, 아래의 메커니즘에 의해 Verification 단계가 수행된다 :</p>
<blockquote>
<p>Mobile GUI Agent가 UI action을 생성한다.</p>
<p>→ 사전에 정의된 develoepr library를 통해 <em>예상되는</em> state update가 반환된다.</p>
<p>→ 이 값을 기반으로 <em>state predicate</em>들의 true/false 여부를 재평가한다.</p>
</blockquote>
<p>검증은 Predicate-level과 Rule-level의 두 가지 단계에서 이루어진다. </p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/4ec03eb4-65d1-41c3-bb5e-52d00028edc0/image.png" alt=""></p>
<p>다시 DSL 구조 시각화 자료를 보면 이해가 쉬울 것이다.</p>
<ol>
<li><p><strong><em>Predicate-level Verification :</em></strong> 이 단계의 검증은 <strong>‘모든 상태 업데이트’</strong>마다 수행된다. </p>
<p> 만약, 여기서 p<em>redicate</em>가 false로 평가되어도, 이는 에러를 의미하는 것이 아니다. 그 이유는, 유저 지시사항을 중간 단계에서 업데이트가 진행되고 있는 중일 수도 있기 때문이다. (예시로, 사과 3개를 장바구니에 담는 경우 ‘+’ 버튼을 세 번 누르면서 사과의 개수가 1개, 2개로 업데이트되는 중간 상태를 떠올려 볼 수 있다.) </p>
<p> 이때 VSA는 soft feedback을 agent에게 전달하게 된다.</p>
</li>
<li><p><strong>Rule-level Verification :</strong> 이 단계의 검증은 <strong>‘되돌릴 수 없거나 critical한 checkpoint’</strong>에서 수행된다.</p>
<p> 이러한 체크포인트는 되돌릴 수 없는 critical한 action과 관련된 rule이 만족되지 않으면, 해당 action은 무효화되고 차단된다. </p>
<p> VSA는 hard feedback을 agent에게 제공한다.</p>
</li>
</ol>
<h2 id="structured-feedback-generator---for-solution-3">Structured Feedback Generator - for Solution 3</h2>
<hr>
<p>VSA와 같은 검증 시스템은 Mobile GUI Agent의 action을 검증해 준다는 장점도 있지만, agent에게 피드백을 제공해줄 수 있다는 것 또한 굉장한 장점이다.</p>
<p>VSA는 앞선 검증 결과를 기반으로, 세 가지 종류의 구조화된 피드백을 제공하여 mobile task 자동화의 신뢰성과 안전성을 높인다.</p>
<ol>
<li><strong><em>Roadmap Feedback :</em></strong> logical Specification을 기반으로, 전반적인 경로에 대한 가이드라인을 제공한다 (검증 결과와는 관계x)</li>
<li><strong><em>Predicate-level Soft Feedback :</em></strong> Predicate-level verification이 실패한 경우, agent에게 <strong>일종의 경고로써</strong> soft feedback을 제공한다. 이는 행동을 엄격하게 차단하는 것이 아니므로, agent는 피드백을 참고하되 동일한 action을 다시 수행할 수 있다.</li>
<li><strong><em>Rule-level Hard Feedback :</em></strong> Rule-level verification이 실패한 경우, 이 경우는 critical actions에 대해서 rule-level에서 엄격한 금지와 피드백이 제공된다. 이때는 agent는 <strong>해당 <em>rule</em>을 구성하는 모든 <em>state predicate</em>들이 만족되기 전까지</strong> 동일한 행동을 수행하지 못한다.</li>
</ol>
<h2 id="implementation--evaluation">Implementation &amp; Evaluation</h2>
<hr>
<h3 id="implementation">Implementation</h3>
<ul>
<li>Python으로 구현되었고, Intent Encoder를 구현하기 위해 GPT-4o를 활용한다.</li>
<li>Developer Library 구현에 대한 문서와 가이드라인을 제공하여 개발자가 효과적으로 State Predicates를 정의하고 활용할 수 있도록 한다.</li>
<li>OpenAI의 text-embedding-3-small model을 사용하여 user instruction의 ‘구조적 일치(structural equivalence)’ 대신 ‘의미적 일치(semantic equivalence)’를 판단한다.</li>
</ul>
<h3 id="dataset">Dataset</h3>
<ul>
<li>300개의 user instruction에 대한 dataset을 활용해서 Evaluation을 진행한다. (150 correct + 150 wrong)</li>
<li>이들 중 125개의 correct와 125개의 wrong dataset은 널리 사용되고 있는 데이터셋인 <strong><em>LlamaTouch</em></strong>의 일부를 활용했다.</li>
<li>다만, <strong><em>LlamaTouch</em></strong>는 상대적으로 단순한 instruction들로 구성되어 있으므로 (avg. 5.67 steps), 연구진은 더 복잡한 (avg. 19.16 steps, max. 40 steps) 25개의 correct, 25개의 wrong instruction들로 이루어진 <strong><em>Challenge Dataset</em></strong>을 직접 구성하여 추가로 확보했다.</li>
</ul>
<h3 id="evaluation">Evaluation</h3>
<p><img src="https://velog.velcdn.com/images/h_channni/post/7c18a00e-b406-41d7-873a-26e741e8f9ab/image.png" alt=""></p>
<p>실험을 진행한 결과, VSA를 적용한 경우에 LlamaTouch Dataset과 Challenge Dataset에서 모두 Reflection 방법에 비해 더 높은 검증 정확도를 보이는 것을 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/045a0f40-36b1-41f7-9f00-21810f9a174c/image.png" alt=""></p>
<p>특히 Challenge Dataset에 대해서 여러 번 반복시켰을 때 VSA의 검증 정확도가 크게 상승한다는 것을 확인할 수 있다. 이는 검증이 logical formula에 기반해서 이루어지기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/f9ef60ae-c1dc-45a2-ab72-bfb01d353d11/image.png" alt=""></p>
<p>피드백의 영향 또한 확인할 수 있다. </p>
<p>Challenge Dataset에서, 두 가지 Reflection의 경우 피드백을 거쳤더라도 실패했던 case를 다시 성공시키지 못했던 반면, VSA가 피드백을 적용한 이후 Agent는 기존에 실패했던 많은 instruction들을 성공시키는 효과를 보여주었다. 이는 구조화된 피드백의 강력한 영향력을 보여준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nomad Coders ‘플러터 10주 챌린지’ 4기 3주차 주간회고]]></title>
            <link>https://velog.io/@h_channni/Nomad-Coders-%ED%94%8C%EB%9F%AC%ED%84%B0-10%EC%A3%BC-%EC%B1%8C%EB%A6%B0%EC%A7%80-4%EA%B8%B0-3%EC%A3%BC%EC%B0%A8-%EC%A3%BC%EA%B0%84%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@h_channni/Nomad-Coders-%ED%94%8C%EB%9F%AC%ED%84%B0-10%EC%A3%BC-%EC%B1%8C%EB%A6%B0%EC%A7%80-4%EA%B8%B0-3%EC%A3%BC%EC%B0%A8-%EC%A3%BC%EA%B0%84%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Fri, 24 Jan 2025 07:16:29 GMT</pubDate>
            <description><![CDATA[<h1 id="3주차-주간회고">3주차 주간회고</h1>
<p><a href="https://velog.velcdn.com/images/h_channni/post/81c69bc8-f1f6-4207-98e4-77f46f0962b5/image.png"></a></p>
<p>눈 감았다 떳는데 벌써 이번주 주간회고를 제출해야 하는 시간이 되었다.</p>
<p>내가 이번주에 뭘 했지 ….. ?</p>
<p>그러고 보니 벌써 1월도 다 끝나가네 ..? 시간에 버그난 것 같다(그렇다고 믿고 싶다)</p>
<br/>

<p>좋은 소식이 있다면 .. 상하이로 해외여행(2.10~13)만 다녀와서 자대 랩실에 학부연구생으로 합류할 것 같다!</p>
<p>기대 반 걱정 반 … 그래도 교수님께서 참 인자하셔서 다행이다.</p>
<p>이번주에 연구실 컨택 준비한다고 시간을 너무 많이 뺏기긴 했지만 (벌써부터 밀리기 시작한다 ..~) 그래도 결과가 좋아서 다행이다.</p>
<p>이렇게 또 한 단계 스텝업 하는거겠지!
<br/></p>
<p>대신, 그만큼 바빠질 것 같다. 지금보다 더 바빠진다는게 아주 두렵긴 하지만 ..</p>
<p>심신에 부작용이 생기지 않게 관리를 잘 해야 할 필요성이 느껴진다. 방법은 잘 모르겠지만, 안 그러면 어느 쪽으로든 문제가 생길 것 같다. </p>
<h2 id="핵심-3줄-요약">핵심 3줄 요약</h2>
<ul>
<li>와 바쁘다 ! 연구실 컨택에 동아리 운영진에 다른 프로젝트에 스터디까지 ..</li>
<li>틱톡 클론코딩 강의 시작! 이 강의를 완전 처음 듣는 거라 그만큼 시간이 더 오래 걸리는 것 같다.</li>
<li>몸과 마음을 더 잘 챙길 수 있도록 해야 할 듯.<br/>

</li>
</ul>
<h2 id="잘한-점">잘한 점</h2>
<ul>
<li>틱톡 클론코딩 챌린지, 그래도 꾸역꾸역 진도는 맞췄다! (강의 수강 &amp; 챌린지 과제 제출)</li>
<li>운동을 다시 시작했다. 더 자주 가자!<br/>

</li>
</ul>
<h2 id="개선할-점">개선할 점</h2>
<ul>
<li>코드 리팩토링이나 다른 분들 코드리뷰를 제대로 못 했다. 챌린지 두 번째 과제가 첫 번째와 이어지는 만큼 이거부터  해보자.</li>
<li>번아웃 위기 ..? 일이 쌓여있는데 너무 손에 안 잡혀서 반 놓아버렸다가 다시 정신 차림 ..</li>
<li>시간이 후달리기 시작하니까 플러터 학습의 깊이가 얕아지는 것 같다. 단순히 강의 내용 습득이 아니라 더 고차원적으로 접근하려는 시도를 해야 할 듯<br/>

</li>
</ul>
<h2 id="일일-스프린트">일일 스프린트</h2>
<ul>
<li><p>25/01/20 (월)
[⏩] 틱톡 클론코딩: #2.0~#4.4 수강
[✅] 지난주 과제 README 파일 작성 &amp; 수정
[⏩] 코드리뷰 보고 댓글달기 !
[✅] 교수님 컨택 메일 발송
[⏩] 운동
일일회고: 볼링동아리 정기전 스근하게 다녀와서 뻗어버림 .. 전날 밤샌 여파가 ..ㅜ</p>
</li>
<li><p>25/01/22 (수)
  [✅] 운동가기
  [✅] 오상은 교수님 연구실 방문 11:00
  [✅] 케이웹 운영진 회의 13:00
  [✅] 스터디 주간회의 참석 20:00
  [✅] 틱톡 클론코딩 ~#4.10 수강
  [✅] 틱톡챌린지 과제 제출
 일일회고: 밤새 챌린지 과제 겨우 끝내고 얼레벌레 낸 것 같다. 쉽지 않구만 ..</p>
</li>
<li><p>2025/01/23 (목)
[⏩] 운동하기
[⏩] 틱톡 클론 강의 #5.0 ~#5.4
[⏩] 지난 챌린지 리팩토링
[⏩] 다른분들 코드리뷰 보고 공부 + 댓글
일일회고: 어제의 여파로 늦잠이슈 + 나태지옥에 빠져버림 .. 벌써부터 이런 징조가 보이면 안 되는데 …?</p>
</li>
<li><p>2025/01/24 (금)
  [] 틱톡 클론 강의 #5.0~#5.4
  [] 주간회고 작성
  [] 백준 PS 1문제 풀기</p>
<br/>

</li>
</ul>
<h2 id="이번주-배운-내용">이번주 배운 내용</h2>
<p>(틱톡 클론코딩 Ch4까지 내용 기준.. Ch5부터는 아직 못 들었다 ㅜ)</p>
<p>이번주는 <strong>UI 관련해서 집중적으로 배운 한 주</strong>였다.</p>
<p>다른 위젯들도 모두 새로 배운 것들이지만, <code>TextField</code> 위젯이 특히 기억에 남는 것 같다.
<img src="https://velog.velcdn.com/images/h_channni/post/4f0937c0-455e-4488-a306-78bf0b5fce1c/image.png" alt="Textfield example"></p>
<p>→ 이런 디자인에, Error 스타일이나 Label 스타일까지 ..</p>
<p>이전에 React로 웹 프론트엔드를 공부할 때, 비슷한 디자인을 만들어보려고 정말 개고생했던 (…) 기억이 떠올랐는데, 이게 기본적으로 적용되어서 갖다 쓰기만 하면 된다는 게 참 신세계였다.</p>
<p>그 밖에도, 니꼬쌤의 의도대로 인터페이스를 구성할 수 있는 <strong>다양한 위젯들을 직접 사용해보면서 공부할 수 있어서</strong> 좋았다. 역시 이런 강의 스타일이 내가 니꼬쌤 강의를 좋아하는 이유이자 주변 친구들에게도 강력하게 추천하는 이유인 듯하다.
<br/></p>
<h2 id="마무리">마무리</h2>
<p>다음주는 설 명절이라 챌린지가 없다 !</p>
<p>개인적으로는 다음주가 판 뒤집을 기회라고 생각중이다 … ㅋㅋㅋ 다음주에 복습과 예습을 잔뜩 해놔서 다시 한 번 스터디 따라갈 동력을 확보하는 게 목표이다.
<br/>!</p>
<p>긴 회고 읽어 주셔서 감사합니다!</p>
<p>모두들 명절 잘 보내시고 함께 화이팅해봐요 ~~ :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nomad Coders ‘플러터 10주 챌린지’ 4기 2주차 주간회고]]></title>
            <link>https://velog.io/@h_channni/Nomad-Coders-%ED%94%8C%EB%9F%AC%ED%84%B0-10%EC%A3%BC-%EC%B1%8C%EB%A6%B0%EC%A7%80-4%EA%B8%B0-2%EC%A3%BC%EC%B0%A8-%EC%A3%BC%EA%B0%84%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@h_channni/Nomad-Coders-%ED%94%8C%EB%9F%AC%ED%84%B0-10%EC%A3%BC-%EC%B1%8C%EB%A6%B0%EC%A7%80-4%EA%B8%B0-2%EC%A3%BC%EC%B0%A8-%EC%A3%BC%EA%B0%84%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 19 Jan 2025 20:27:16 GMT</pubDate>
            <description><![CDATA[<h1 id="2주차">2주차</h1>
<p>Nomad Coders ‘플러터 10주 챌린지’ 4기 2주차 주간회고록입니다.</p>
<hr>
<p>chill guy 밈에 빠져버렸습니다. (디코 프사까지 전격 교체 .. 누오야미안해)</p>
<p><a href="https://www.youtube.com/watch?v=hMuoeP-lbS4&amp;t=2311s">https://www.youtube.com/watch?v=hMuoeP-lbS4&amp;t=2311s</a>
chill guy 브금과 함께 코딩하는 삶 (노동요 추천에도 올려야지)</p>
<p>코드에서 버그가 터져도 고chill 수 있는 chill guy인 나:</p>
<p>이것저것 바쁜 우리네 인생이지만 chill하게 살자구요 ~</p>
<hr>
<h3 id="✅-핵심-3줄-요약">✅ 핵심 3줄 요약</h3>
<ul>
<li>벌써 밀리기 시작한다 .. 정신 바짝 차려야 할 듯</li>
<li>강의를 들을 때 시간 분배를 훨씬 넉넉하게 해야 할 것 같다.</li>
<li>코드리뷰 열심히 동참하기!!</li>
</ul>
<h3 id="✅-이번-주-목표">✅ 이번 주 목표</h3>
<p>[x]  &#39;플러터로 웹툰 앱 만들기&#39; 강의 <strong>필기 하면서</strong> 완강
[x]  챌린지 과제 밀리지 않고 제출
[ ]  일일 스프린트 매일 올리기</p>
<h3 id="✅-잘한-점">✅ 잘한 점</h3>
<ul>
<li>강의 완강 &amp; 챌린지 모든 과제 제출 성공!</li>
<li>시간이 오래 걸렸지만, 강의 내용 필기를 착실히 하면서 들었다.</li>
</ul>
<h3 id="✅-개선할-점">✅ 개선할 점</h3>
<ul>
<li>일일 스프린트를 빼먹은 날이 많았다. 다음주는 매일매일 올리기!</li>
<li>코드 챌린지를 수행할 때 딱 필수 사항만 충족해서 제출했다.</li>
<li>디스코드 활동이 부족했다.</li>
</ul>
<h3 id="✅-이번-주-배운-내용">✅ 이번 주 배운 내용</h3>
<p><img src="https://velog.velcdn.com/images/h_channni/post/8b6e7591-8711-4615-9215-fb7e137c5531/image.png" alt="스터디 내용정리!"></p>
<p>(강의 필기 내용정리 일부분 캡처. 각 행마다 페이지를 만들어서 필기하고 → 중요한 부분은 따로 메모하면서 공부중입니다!)</p>
<ul>
<li>플러터의 핵심이 되는 <code>Widget</code> 에 대해 많은 내용을 배웠다.</li>
<li>‘이런 게 기본으로 제공된다고?’ 하는 것들이 많아서 놀랐다. (특히 <code>ListView</code> 나 <code>Navigator</code> 같은 UI 관련 기능들) 플러터 배우길 참 잘했다는 생각을 하면서 ..~</li>
<li>API Fetching 관련 구조 (model, service, etc.), HTTP Method 호출, async-await 문법 등은 기존 백엔드 개발에서의 그것과 유사하다.</li>
<li>Code Actions는 플러터 개발자의 삶의 질을 지켜준다. 참 좋은 기능이지만, 이 기능이 없었다면 많은 앱 개발자들이 플러터를 애초에 선택하지 않았을 것 같기도 하다. 개발자들을 유인하기 위해선 필수불가결한 기능이 아니었을까?</li>
</ul>
<h3 id="✅-주간회의-온라인-단체-커피챗">✅ 주간회의 (온라인 단체 커피챗)</h3>
<ul>
<li>또 한 번 스터디원 분들의 넓은 스펙트럼에 놀랐다. 진짜 대단하신 분들이 많은 것 같다.</li>
<li>아직 대학생인 나보단 대부분의 분들이 경험이나 커리어가 비교도 안 될 만큼 깊고 풍부하신 것 같다는 느낌을 받았다. 뭔가 다들 말을 잘 하시는 느낌 ..? 이 들어서 내 답변이 조금 부끄럽기도 했던 것 같다.</li>
<li>앞으로 진행될 조별 활동도 기대된다!</li>
</ul>
<hr>
<p>감사합니다 😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - 제네릭(Generic) & 트레이트(Trait)]]></title>
            <link>https://velog.io/@h_channni/Rust-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric-%ED%8A%B8%EB%A0%88%EC%9D%B4%ED%8A%B8Trait</link>
            <guid>https://velog.io/@h_channni/Rust-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric-%ED%8A%B8%EB%A0%88%EC%9D%B4%ED%8A%B8Trait</guid>
            <pubDate>Tue, 03 Dec 2024 07:52:38 GMT</pubDate>
            <description><![CDATA[<p>Rust에 존재하는 <em>제네릭 (Generic), 트레이트 (Trait), 라이프타임 (Lifetime)</em> 개념에 대해 공부하고, 정리해 보겠습니다.</p>
<h2 id="제네릭-중복되는-타입-효율적으로-처리하기-위한-도구">제네릭: 중복되는 타입 효율적으로 처리하기 위한 도구</h2>
<div style="border: 1px solid #000000; border-radius: 5px; padding: 10px; background-color: #FFFFFF;">
  🦀 <strong> 제네릭 (generic)</strong><br>
  모든 프로그래밍 언어는 중복되는 개념을 효율적으로 처리하기 위한 도구를 가지고 있습니다. 러스트에서는 <em>제네릭 (generic)</em> 이 그 역할을 맡습니다.  
<br>
제네릭은 구체(concrete) 타입 혹은 기타 속성에 대한 추상화된 대역입니다. 컴파일과 실행 시점에 제네릭들이 실제로 무슨 타입으로 채워지는지 알 필요 없이 제네릭의 동작이나 다른 제네릭과의 관계를 표현할 수 있습니다.
</div>

<p>교재에 나와 있는 제네릭에 대한 설명입니다. 다시 요약하자면, <strong>러스트에서는 타입을 추상화하는 도구로 제네릭을 사용합니다.</strong> </p>
<p>반복되는 코드 블록을 여러 번 반복해서 작성하는 대신 ‘함수’로 만들어서 재사용하는 개념을 떠올려보면 제네릭을 이해하는 데 도움이 될 것 같습니다. </p>
<p>제네릭을 사용하면 타입과 기능을 일반화하여 코드 중복을 줄이고 유지보수성을 향상시킬 수 있습니다. </p>
<p>제네릭은 타입 매개변수를 사용하여 구현되며, 이는 코드가 사용될 때 구체적인 타입으로 지정될 placeholder 역할을 합니다.</p>
<p>함수의 매개변수나 반환 타입, 구조체, 열거형, 메서드 등에서 경우에 따라 여러 타입을 사용해야 할 수도 있습니다. 이때, 제네릭이 빛을 발하게 됩니다. </p>
<h3 id="제네릭-사용-예시-코드">제네릭 사용 예시 코드</h3>
<pre><code class="language-rust">// 제네릭 함수 정의
fn largest&lt;T&gt;(list: &amp;[T]) -&gt; &amp;T {
    let mut largest = &amp;list[0];

    for item in list {
        if item &gt; largest {
            largest = item;
        }
    }

    largest
}

// 제네릭 구조체 정의
struct Point&lt;T&gt; {
    x: T,
    y: T,
}

fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}

// 제네릭 열거형 정의 - Option&lt;T&gt;, Result&lt;T, E&gt;
enum Option&lt;T&gt; {
    Some(T),
    None,
}

enum Result&lt;T, E&gt; {
    Ok(T),
    Err(E),
}

// 제네릭 메서드 정의
struct Point&lt;X1, Y1&gt; {
    x: X1,
    y: Y1,
}

impl&lt;X1, Y1&gt; Point&lt;X1, Y1&gt; {
    fn mixup&lt;X2, Y2&gt;(self, other: Point&lt;X2, Y2&gt;) -&gt; Point&lt;X1, Y2&gt; {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}</code></pre>
<p>제네릭을 사용할 때는 <code>&lt;&gt;</code> 꺾쇠괄호 안에 타입 매개변수의 이름을 작성해 줘야 합니다. (관행적으로 Type의 첫 글자를 딴 <code>T</code>를 사용합니다.) </p>
<p>함수나 구조체, 열거형, <code>impl</code> 키워드 바로 뒤에 <code>&lt;T&gt;</code> 를 붙여 타입 매개변수 이름을 선언하고 각각의 정의 내에서 구체적인 타입 대신 타입 매개변수 이름을 활용하면 됩니다!</p>
<h2 id="트레이트-공통된-동작을-정의하기">트레이트: 공통된 동작을 정의하기</h2>
<div style="border: 1px solid #000000; border-radius: 5px; padding: 10px; background-color: #FFFFFF;">
  🦀 <strong>트레이트 (trait)</strong><br>
<em>트레이트 (trait)</em> 는 특정한 타입이 가지고 있으면서 다른 타입과 공유할 수 있는 기능을 정의합니다. 트레이트를 사용하면 공통된 기능을 추상적으로 정의할 수 있습니다. <br>
  <em>트레이트 바운드 (trait bound)</em> 를 이용하면 어떤 제네릭 타입 자리에 특정한 동작을 갖춘 타입이 올 수 있음을 명시할 수 있습니다.
</div>

<p><strong>(Note: 약간의 차이는 있으나, 트레이트는 다른 언어에서 흔히 <em>인터페이스 (interface)</em> 라고 부르는 기능과 유사합니다.)</strong></p>
<h3 id="여러-타입type의-공통된-행위특성을-표시한-것을-trait-라고-합니다"><strong>여러 타입(type)의 공통된 행위/특성을 표시한 것을 Trait 라고 합니다.</strong></h3>
<pre><code class="language-rust">// Summary 트레이트 정의
pub trait Summary {
    fn summarize(&amp;self) -&gt; String;
}</code></pre>
<p>우리는 러스트에서 트레이트를 활용해서, 다양한 타입들이 공통적으로 갖는 동작에 대해 추상화할 수 있습니다. 마치 객체지향 프로그래밍의 인터페이스처럼 말이죠! 
트레이트를 통해 우리는 코드의 재사용성, 유연성, 안전성을 높일 수 있습니다.</p>
<p>위의 트레이트 정의 예시에서, 메서드 시그니처 뒤에는 중괄호로 시작하여 메서드를 구현하는 대신 세미콜론을 집어넣었습니다. 이 트레이트를 구현하는 각 타입이 메서드에 맞는 동작을 직접 제공해야 합니다. 
컴파일러는 <code>Summary</code> 트레이트가 있는 모든 타입에 정확히 이와 같은 시그니처의 <code>summarize</code> 메서드를 가지고 있도록 강제할 것입니다.</p>
<h3 id="특정-타입에-트레이트-구현하기">특정 타입에 트레이트 구현하기</h3>
<pre><code class="language-rust">pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&amp;self) -&gt; String {
        format!(&quot;{}, by {} ({})&quot;, self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&amp;self) -&gt; String {
        format!(&quot;{}: {}&quot;, self.username, self.content)
    }
}</code></pre>
<p>이 예시에서는 <code>NewsArticle</code> 과 <code>Tweet</code> 타입에 각각 <code>Summary</code> 트레이트를 구현하였습니다. </p>
<p>특정 타입에 트레이트를 구현하는 문법은 위 예시에서 확인할 수 있듯이,</p>
<pre><code class="language-rust">impl Trait for Type { }</code></pre>
<p>형태로 명시한 다음, 트레이트 정의에 정의된 메서드 시그니처에 대한 메서드 본문을 작성해주면 됩니다.</p>
<h2 id="트레이트-바운드-trait-bound-제네릭과-트레이트를-활용한-rust의-유연하면서도-강력한-기능">트레이트 바운드 (trait bound): 제네릭과 트레이트를 활용한 Rust의 유연하면서도 강력한 기능</h2>
<p>앞서 소개한 제네릭과 트레이트를 함께 사용하는 방법으로 트레이트 바운드가 있습니다.</p>
<p><strong>트레이트 바운드는 제네릭에 제약을 걸어, 특정 동작을 보장하는 방법입니다.</strong> 즉, 제네릭 타입이 특정 트레이트를 구현한 타입이어야 한다는 조건을 명시해둔 것입니다.</p>
<p>이를 통해, 다양한 이점을 얻을 수 있는데, 아래와 같습니다:</p>
<ul>
<li>컴파일러에게 제네릭 타입이 어떤 기능을 가져야 하는지 알려주고, 컴파일 시점에 타입 검사를 실행하여 런타임 오류를 방지할 수 있습니다.</li>
<li>함수나 구조체가 구현해야 하는 기능을 명확히 표현해둘 수 있습니다.</li>
<li>트레이트 바운드를 통해 Rust는 강력한 타입 시스템을 유지하면서도 유연한 제네릭 프로그래밍을 가능하게 합니다.</li>
</ul>
<pre><code class="language-rust">pub fn notify&lt;T: Summary&gt;(item: &amp;T) {
    println!(&quot;Breaking news! {}&quot;, item.summarize());
}</code></pre>
<p>트레이트는, 꺾쇠괄호 안의 제네릭 타입 매개변수 선언 뒤에 콜론(<code>:</code>)과 함께 위치하게 됩니다.</p>
<p>이제, <code>notify</code> 함수의 <code>item</code> 매개변수로 올 수 있는 타입은 <code>Summary</code> 트레이트를 구현한 타입으로 제한됩니다.</p>
<pre><code class="language-rust">pub fn notify&lt;T: Summary + Display&gt;(item: &amp;T) {</code></pre>
<p>위와 같이 <code>+</code> 구문으로 여러 개의 트레이트를 모두 구현하도록 바운드를 설정할 수도 있습니다.</p>
<pre><code class="language-rust">fn some_function&lt;T, U&gt;(t: &amp;T, u: &amp;U) -&gt; i32
where
    T: Display + Clone,
    U: Clone + Debug,
{</code></pre>
<p>위 예시는 <code>where</code> 조항입니다. </p>
<p>트레이트 바운드가 복잡해지면 자칫 코드의 가독성을 해칠 수 있습니다. 이때, 트레이트 바운드의 내용은 <code>where</code> 조항으로 따로 빼 버리면 함수 시그니처를 읽기가 더욱 쉬워질 것입니다.
<br /></p>
<p>읽어주셔서 감사합니다 🙇‍♂️</p>
<h2 id="references">References</h2>
<p><a href="https://doc.rust-kr.org/ch10-01-syntax.html">https://doc.rust-kr.org/ch10-01-syntax.html</a></p>
<p><a href="https://doc.rust-kr.org/ch10-02-traits.html">https://doc.rust-kr.org/ch10-02-traits.html</a></p>
<p><a href="https://www.linkedin.com/pulse/generics-rust-amit-nadiger">https://www.linkedin.com/pulse/generics-rust-amit-nadiger</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - 에러 처리 (Error handling)]]></title>
            <link>https://velog.io/@h_channni/Rust-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC-Error-handling</link>
            <guid>https://velog.io/@h_channni/Rust-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC-Error-handling</guid>
            <pubDate>Mon, 11 Nov 2024 05:54:46 GMT</pubDate>
            <description><![CDATA[<p>“소프트웨어에서 에러는 삶의 일부이므로, 러스트는 뭔가 잘못되는 상황을 처리하기 위한 기능을 몇 가지 갖추고 있습니다.” 라는 Rust 교재의 말처럼, 개발을 하는 과정에서 발생하는 수많은 에러를 우리는 해결해야 합니다. Rust의 에러 처리에 대해 공부하고, 정리해 보겠습니다.</p>
<p>대부분의 경우 러스트에서는 코드가 컴파일 되기 전에 에러의 가능성을 인지하고 조치를 취해야 합니다. 이러한 요구사항은 여러분의 코드를 프로덕션 환경에 배포하기 전에 에러를 발견하고 적절히 조치할 것을 보장하여 여러분의 프로그램을 더 견고하게 해 줍니다!</p>
<p>러스트는 에러를 <em>복구 가능한 (recoverable)</em> 에러와 <em>복구 불가능한 (unrecoverable)</em> 에러 두 가지 범주로 묶습니다. </p>
<ul>
<li>복구 가능한 에러: <code>Result&lt;T, E&gt;</code> 타입</li>
<li>복구 불가능한 에러: <code>panic!</code> 매크로 (에러가 발생했을 때 프로그램을 종료함)<br />
## panic!으로 복구 불가능한 에러 처리하기

</li>
</ul>
<p>가끔은 코드에서 나쁜 일이 일어나고, 이에 대해 여러분이 할 수 있는 것이 없을 수도 있습니다. 이런 경우를 위해 러스트에는 <code>panic!</code> 매크로가 있습니다. </p>
<p>실제로 패닉을 일으키는 두 가지 방법이 있습니다.</p>
<ol>
<li>코드가 패닉을 일으킬 동작을 하는 것</li>
<li><code>panic!</code> 매크로를 명시적으로 호출하는 것</li>
</ol>
<p>패닉이 일어나면 ..</p>
<ul>
<li><p>실패 메시지를 출력하고</p>
</li>
<li><p>되감고 (unwind)</p>
</li>
<li><p>스택을 청소하고 (+ backtrace information을 만들 수도 있다.)</p>
</li>
<li><p>종료합니다.</p>
<br />
```rust
fn main() {
  let v = vec![1, 2, 3];

<p>  v[99];
}</p>
<pre><code></code></pre></li>
</ul>
<p>벡터의 유효한 범위를 넘어선 인덱스로 접근을 시도하는 예시 코드를 통해 에러를 발생시켜 보겠습니다.</p>
<pre><code class="language-bash">$ cargo run
   Compiling panic v0.1.0 (file:///projects/panic)
    Finished dev [unoptimized + debuginfo] target(s) in 0.27s
     Running `target/debug/panic`
thread &#39;main&#39; panicked at &#39;index out of bounds: the len is 3 but the index is 99&#39;, src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
</code></pre>
<ul>
<li>첫번째 줄은 99 인덱스로 접근을 시도한 <code>main.rs</code> 4번째 줄을 가리키고 있습니다.</li>
<li>그다음 줄은 <code>RUST_BACKTRACE</code> 환경 변수를 설정하여 에러의 원인이 무엇인지 정확하게 백트레이스할 수 있다고 말해주고 있습니다.</li>
</ul>
<p>한번 <code>RUST_BACKTRACE</code> 환경변수를 0이 아닌 값으로 설정하여 백트레이스를 얻어봅시다. 아래의 코드 블록은 여러분이 보게 될 것과 유사한 출력을 나타냅니다.</p>
<pre><code class="language-bash">$ RUST_BACKTRACE=1 cargo run
thread &#39;main&#39; panicked at &#39;index out of bounds: the len is 3 but the index is 99&#39;, src/main.rs:4:5
stack backtrace:
   0: rust_begin_unwind
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:142:14
   2: core::panicking::panic_bounds_check
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/panicking.rs:84:5
   3: &lt;usize as core::slice::index::SliceIndex&lt;[T]&gt;&gt;::index
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/slice/index.rs:242:10
   4: core::slice::index::&lt;impl core::ops::index::Index&lt;I&gt; for [T]&gt;::index
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/slice/index.rs:18:9
   5: &lt;alloc::vec::Vec&lt;T,A&gt; as core::ops::index::Index&lt;I&gt;&gt;::index
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/alloc/src/vec/mod.rs:2591:9
   6: panic::main
             at ./src/main.rs:4:5
   7: core::ops::function::FnOnce::call_once
             at /rustc/e092d0b6b43f2de967af0887873151bb1c0b18d3/library/core/src/ops/function.rs:248:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
</code></pre>
<ul>
<li><em>백트레이스 (backtrace)</em> 란 어떤 지점에 도달하기까지 호출한 모든 함수의 목록을 말합니다.</li>
<li>백트레이스를 읽는 요령은 위에서부터 시작하여 여러분이 작성한 파일이 보일 때까지 읽는 것입니다. 그곳이 바로 문제를 일으킨 지점입니다.</li>
<li>여러분의 파일이 나타난 줄보다 위에 있는 줄은 여러분의 코드가 호출한 코드이고, 아래의 코드는 여러분의 코드를 호출한 코드입니다. → panic이 발생한 지점을 전후로 더 정확한 실행 기록을 추적해볼 수 있습니다.</li>
<li>이 전후의 줄에는 핵심 러스트 코드, 표준 라이브러리, 여러분이 이용하고 있는 크레이트가 포함될 수 있습니다.<br />
## Result로 복구 가능한 에러 처리하기

</li>
</ul>
<p>대부분 에러는 프로그램을 전부 중단해야 할 정도로 심각하진 않습니다. </p>
<p>때때로 어떤 함수가 실패할 경우는 쉽게 해석하고 대응할 수 있는 원인 때문입니다. 예를 들어 어떤 파일을 열려고 했는데 해당 파일이 존재하지 않아서 실패했다면, 프로세스를 종료해 버리는 대신 파일을 생성하는 것을 원할지도 모르죠.</p>
<pre><code class="language-rust">enum Result&lt;T, E&gt; {
    Ok(T),
    Err(E),
}</code></pre>
<ul>
<li><code>Result</code> 열거형은 <code>Ok</code>와 <code>Err</code>라는 두 개의 배리언트를 갖고 있습니다.</li>
<li><code>T</code>와 <code>E</code>는 제네릭 타입 매개변수입니다. (교재의 10장에서 자세히 다루게 되는 내용)
  → <code>T</code>는 성공한 경우 <code>Ok</code> 배리언트 안에 반환될 값의 타입을 나타냅니다.
  → <code>E</code>는 실패한 경우 <code>Err</code> 배리언트 안에 반환될 에러의 타입을 나타냅니다.</li>
</ul>
<pre><code class="language-rust">use std::fs::File;

fn main() {
    let greeting_file_result = File::open(&quot;hello.txt&quot;);

    let greeting_file = match greeting_file_result {
        Ok(file) =&gt; file,
        Err(error) =&gt; panic!(&quot;Problem opening the file: {:?}&quot;, error),
    };
}</code></pre>
<p>→ 예제: <code>File::open</code> 반환 값에 따라 다르게 작동하는 코드</p>
<ul>
<li><p><code>File::open</code>의 반환 타입은 <code>Result&lt;T, E&gt;</code>입니다.</p>
</li>
<li><p><code>File::open</code>이 성공한 경우에는 <code>greeting_file_result</code> 변수의 값이 파일 핸들을 가지고 있는 <code>Ok</code> 인스턴스가 될 것입니다.</p>
</li>
<li><p>실패한 경우 <code>greeting_file_result</code>는 발생한 에러의 종류에 관한 더 자세한 정보가 담긴 <code>Err</code> 인스턴스가 될 것입니다.</p>
</li>
<li><p><code>Option</code> 열거형과 같이 <code>Result</code> 열거형과 배리언트들은 프렐루드로부터 가져와진다는 점을 주의하세요. 따라서 <code>match</code> 갈래의 <code>Ok</code>와 <code>Err</code> 앞에 <code>Result::</code>라고 지정하지 않아도 됩니다.</p>
<br />
### 에러 발생 시 패닉을 위한 숏컷: `unwrap`과 `expect`
</li>
<li><p><code>unwrap</code> 메서드는 예제 9-4에서 작성한 <code>match</code> 구문과 비슷한 구현을 한 숏컷 메서드입니다.</p>
<ul>
<li>만일 <code>Result</code> 값이 <code>Ok</code> 배리언트라면, <code>unwrap</code>은 <code>Ok</code> 내의 값을 반환할 것입니다.</li>
<li>만일 <code>Result</code>가 <code>Err</code> 배리언트라면 <code>unwrap</code>은 <code>panic!</code> 매크로를 호출해줄 것입니다.</li>
<li>아래에 <code>unwrap</code>이 동작하는 예가 있습니다:</li>
</ul>
</li>
</ul>
<pre><code class="language-rust">        use std::fs::File;

        fn main() {
            let greeting_file = File::open(&quot;hello.txt&quot;).unwrap();
        }</code></pre>
<ul>
<li><p>이와 비슷한 <code>expect</code>는 <code>panic!</code> 에러 메시지도 선택할 수 있도록 해 줍니다.</p>
<ul>
<li><p><code>unwrap</code> 대신 <code>expect</code>를 이용하고 좋은 에러 메시지를 제공하면 여러분의 의도를 전달하면서 패닉의 근원을 추적하는 걸 쉽게 해줍니다.</p>
</li>
<li><p><code>expect</code>의 문법은 아래와 같이 생겼습니다:</p>
<pre><code class="language-rust">use std::fs::File;

fn main() {
    let greeting_file = File::open(&quot;hello.txt&quot;)
        .expect(&quot;hello.txt should be included in this project&quot;);
}</code></pre>
</li>
<li><p><strong>프로덕션급 품질의 코드에서 대부분의 러스타시안은 <code>unwrap</code>보다 <code>expect</code>를 선택하여 해당 연산이 항시 성공한다고 기대하는 이유에 대한 더 많은 맥락을 제공합니다.</strong> 이렇게 하면 가정이 틀렸다는 것이 입증될 경우 디버깅에 사용할 더 많은 정보를 확보할 수 있습니다. (추후 러스트로 개발할 때 이 내용을 참고하면 좋을 것 같습니다!)</p>
<br />
### 에러 전파하기 (propagating)

</li>
</ul>
</li>
</ul>
<p>함수의 구현체에서 실패할 수도 있는 무언가를 호출할 때, 이 함수에서 에러를 처리하는 대신 <strong>이 함수를 호출하는 코드 쪽으로 에러를 반환</strong>하여 그쪽에서 수행할 작업을 결정하도록 할 수 있습니다. </p>
<p>이를 에러 <em>전파하기 (propagating)</em> 라고 하며 호출하는 코드 쪽에 더 많은 제어권을 주는 것인데, 호출하는 코드 쪽에는 에러를 어떻게 처리해야 하는지 결정하는 정보와 로직이 여러분의 코드 컨텍스트 내에서 활용할 수 있는 것보다 더 많이 있을 수도 있기 때문입니다.</p>
<pre><code class="language-rust">use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -&gt; Result&lt;String, io::Error&gt; {
    let username_file_result = File::open(&quot;hello.txt&quot;);

    let mut username_file = match username_file_result {
        Ok(file) =&gt; file,
        Err(e) =&gt; return Err(e),
    };

    let mut username = String::new();

    match username_file.read_to_string(&amp;mut username) {
        Ok(_) =&gt; Ok(username),
        Err(e) =&gt; Err(e),  // 이 함수의 마지막 표현식이기 때문에 명시적으로 return이라고 적을 필요는 없습니다.
    }
}</code></pre>
<p>→ 파일로부터 사용자 이름을 읽는 함수를 작성한 것입니다. 만일 파일이 존재하지 않거나 읽을 수 없다면, 이 함수는 <strong>호출하는 코드 쪽으로 해당 에러를 반환</strong>할 것입니다.</p>
<ul>
<li>반환 타입: <code>Result&lt;String, io::Error&gt;</code> → 제네릭 매개변수인 <code>&lt;T, E&gt;</code>가 모두 concrete type으로 채워져 있습니다.</li>
<li>만일 이 함수가 문제없이 성공하면, 함수를 호출한 코드는 <code>String</code>(이 함수가 파일로부터 읽어 들인 사용자 이름이겠지요)을 담은 <code>Ok</code> 값을 받을 것입니다.</li>
<li>만일 어떤 문제가 발생한다면, 이 함수를 호출한 코드는 문제가 뭐였는지에 대한 더 많은 정보를 담고 있는 <code>io::Error</code>의 인스턴스를 담은 <code>Err</code> 값을 받을 것입니다.</li>
<li>이 코드를 호출하는 코드는 사용자 이름이 있는 <code>Ok</code> 값 혹은 <code>io::Error</code>를 담은 <code>Err</code> 값을 처리하게 될 것입니다. 이 값을 가지고 어떤 일을 할지에 대한 결정은 호출하는 코드 쪽에 달려 있습니다.
  (만일 그쪽에서 <code>Err</code> 값을 얻었다면, 이를테면 <code>panic!</code>을 호출하여 프로그램을 종료시키는 선택을 할 수도 있고, 기본 사용자 이름을 사용할 수도 있으며, 혹은 파일이 아닌 다른 어딘가에서 사용자 이름을 찾을 수도 있습니다.) <br />
### 에러를 전파하기 위한 숏컷: ?

</li>
</ul>
<pre><code class="language-rust">use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -&gt; Result&lt;String, io::Error&gt; {
    let mut username_file = File::open(&quot;hello.txt&quot;)?;
    let mut username = String::new();
    username_file.read_to_string(&amp;mut username)?;
    Ok(username)
}</code></pre>
<p>→ 위 예제 코드와 같은 기능을 수행하지만, 숏컷인 <code>?</code>를 사용합니다. </p>
<ul>
<li>만일 <code>Result</code>의 값이 <code>Ok</code>라면, <code>Ok</code> 안의 값이 얻어지고 프로그램이 계속됩니다.</li>
<li>만일 값이 <code>Err</code>라면, <code>return</code> 키워드로 에러 값을 호출하는 코드에게 전파하는 것처럼 <code>Err</code>의 값이 반환될 것입니다.</li>
<li><code>?</code>는 <code>?</code>이 사용된 값과 호환 가능한 반환 타입을 가진 함수에서만 사용될 수 있습니다. 
  → <strong>함수의 반환 타입이 <code>Result</code>여야 이 <code>return</code>과 호환 가능합니다.</strong></li>
</ul>
<p>읽어주셔서 감사합니다 🙇‍♂️</p>
<h2 id="references">References</h2>
<p><a href="https://doc.rust-kr.org/ch09-01-unrecoverable-errors-with-panic.html">https://doc.rust-kr.org/ch09-01-unrecoverable-errors-with-panic.html</a></p>
<p><a href="https://doc.rust-kr.org/ch09-02-recoverable-errors-with-result.html">https://doc.rust-kr.org/ch09-02-recoverable-errors-with-result.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - 크레이트(Crate), 패키지(Package), 모듈(Module)]]></title>
            <link>https://velog.io/@h_channni/Rust-%ED%81%AC%EB%A0%88%EC%9D%B4%ED%8A%B8Crate-%ED%8C%A8%ED%82%A4%EC%A7%80Package-%EB%AA%A8%EB%93%88Module</link>
            <guid>https://velog.io/@h_channni/Rust-%ED%81%AC%EB%A0%88%EC%9D%B4%ED%8A%B8Crate-%ED%8C%A8%ED%82%A4%EC%A7%80Package-%EB%AA%A8%EB%93%88Module</guid>
            <pubDate>Sun, 10 Nov 2024 10:33:28 GMT</pubDate>
            <description><![CDATA[<p>프로젝트가 커지면 커질수록 방대해지는 코드를 효율적으로 관리하는 것은 아주 중요합니다. Rust에서 이러한 코드 조직화를 다루기 위해 제공하는 크레이트 / 패키지 / 모듈 개념에 대한 내용을 정리해 보겠습니다.</p>
<h2 id="크레이트-crate">크레이트 (Crate)</h2>
<ul>
<li>Rust가 컴파일 한 차례에 고려하는 가장 작은 코드 단위</li>
<li>바이너리 크레이트와 라이브러리 크레이트 2종류가 있다.</li>
<li>크레이트는 여러 모듈을 담을 수 있다. (모듈은 이 크레이트와 함께 컴파일되는 다른 파일들에 정의되어 있을 수도 있습니다.)</li>
<li><strong>바이너리 크레이트(Binary crate):</strong><ul>
<li>실행 가능한 실행파일로 컴파일할 수 있는 프로그램</li>
<li><code>main</code> 함수를 포함하고 있어야 한다. → 여태껏 만들어 본 모든 크레이트는 바이너리 크레이트였음.</li>
</ul>
</li>
<li><strong>라이브러리 크레이트(Library crate):</strong><ul>
<li><code>main</code> 함수를 가지고 있지 않고, 실행파일의 형태로 컴파일되지 않는다.</li>
<li>대신, <strong>여러 프로젝트에서 공용될 의도로 만들어진 기능들</strong>이 정의되어 있다.</li>
<li>러스타시안들이 ‘크레이트’라 말하는 것은 대부분 라이브러리 크레이트를 의미하는 것이고, 이는 일반적인 프로그래밍 개념에서의 <strong>‘라이브러리’</strong>와 혼용된다.</li>
</ul>
</li>
<li><strong>크레이트 루트(crate root):</strong><ul>
<li>러스트 컴파일러가 컴파일을 시작하는 소스 파일이다.</li>
<li>크레이트의 루트 모듈을 구성한다.</li>
<li>Library crate → <code>src/lib.rs</code> 가 크레이트 루트 &amp;  Binary crate → <code>src/main.rs</code> 가 크레이트 루트.</li>
</ul>
</li>
</ul>
<br />

<h2 id="패키지-package">패키지 (Package)</h2>
<ul>
<li><p>일련의 기능을 제공하는 하나 이상의 crate들의 번들이다.</p>
</li>
<li><p><code>Cargo.toml</code> 파일 포함</p>
</li>
<li><p>적어도 하나의 crate를 포함해야 한다. (Binary든 Library든)</p>
</li>
<li><p>Binary 크레이트는 원하는 만큼 포함할 수 있지만, Library 크레이트는 단 하나만 넣을 수 있다.</p>
</li>
<li><p><code>cargo new</code> 명령어 → 패키지를 만든다.</p>
<pre><code class="language-bash">  $ cargo new my-project
       Created binary (application) `my-project` package

  $ ls my-project
  Cargo.toml
  src

  $ ls my-project/src
  main.rs</code></pre>
</li>
<li><p>현재 패키지는 <em>src/main.rs</em> 만 포함하고 있으므로 이 패키지는 <code>my-project</code>라는 이름의 바이너리 크레이트만으로 구성되어 있습니다.</p>
<p>  만약 어떤 패키지가 <em>src/main.rs</em>와 <em>src/lib.rs</em>를 가지고 있다면 해당 패키지는 패키지와 같은 이름의 바이너리, 라이브러리 크레이트를 포함하게 됩니다. (즉, 한 패키지에 크레이트 2개!)</p>
<p>  <em>src/bin</em> 디렉터리 내에 파일을 배치하면 각각의 파일이 바이너리 크레이트가 되어, 여러 바이너리 크레이트를 패키지에 포함할 수 있습니다.</p>
</li>
</ul>
<br />

<h2 id="모듈-module">모듈 (Module)</h2>
<h3 id="모듈-치트-시트">모듈 치트 시트</h3>
<p><a href="https://doc.rust-kr.org/ch07-02-defining-modules-to-control-scope-and-privacy.html#%EB%AA%A8%EB%93%88-%EC%B9%98%ED%8A%B8-%EC%8B%9C%ED%8A%B8">https://doc.rust-kr.org/ch07-02-defining-modules-to-control-scope-and-privacy.html#모듈-치트-시트</a></p>
<ul>
<li><p><strong>크레이트 루트부터 시작:</strong> 크레이트를 컴파일할 때 컴파일러는 먼저 크레이트 루트 파일을 본다.</p>
</li>
<li><p><strong>모듈 선언:</strong> 크레이트 루트 파일에는 새로운 모듈을 선언할 수 있다; <code>mod garden;</code>이라는 코드로 ‘garden’ 모듈을 선언할 수 있습니다.</p>
<p>  컴파일러는 아래의 장소에서 이 모듈의 코드가 있는지 찾는다.</p>
<ul>
<li><code>mod garden</code> 뒤에 세미콜론 대신 중괄호를 써서 안쪽에 코드를 적은 인라인</li>
<li><em>src/garden.rs</em> 파일 안</li>
<li><em>src/garden/mod.rs</em> 파일 안 (예전 스타일)</li>
</ul>
</li>
<li><p><strong>서브모듈 선언:</strong> crate root가 아닌 다른 파일에서는 서브모듈을 선언할 수 있다. (ex. <em>src/garden.rs</em> 안에 <code>mod vegetables;</code> 를 선언할 수 있다.) → 아래의 장소에서 찾는다.</p>
<ul>
<li><code>mod vegetables</code> 뒤에 세미콜론 대신 중괄호를 써서 안쪽에 코드를 적은 인라인</li>
<li><em>src/garden/vegetables.rs</em> 파일 안</li>
<li><em>src/garden/vegetables/mod.rs</em> 파일 안 (예전 스타일)</li>
</ul>
</li>
<li><p><strong>모듈 내 코드로의 경로</strong>: 일단 모듈이 크레이트의 일부로서 구성되면, 공개 규칙이 허용하는 한도 내에서라면 해당 코드의 경로를 사용하여 동일한 크레이트의 어디에서든 이 모듈의 코드를 참조할 수 있게 됩니다. 예를 들면, garden vegetables 모듈 안에 있는 <code>Asparagus</code> 타입은 <code>crate::garden::vegetables::Asparagus</code>로 찾아 쓸 수 있습니다.</p>
</li>
<li><p><strong>비공개 vs 공개</strong>: 모듈 내의 코드는 기본적으로 <strong><span style="color: red">부모 모듈에게 비공개 (private)</span></strong> 입니다. 모듈을 공개 (public) 로 만들려면, <code>mod</code> 대신 <code>pub mod</code>를 써서 선언하세요. 공개 모듈의 아이템들을 공개하려면 마찬가지로 그 선언 앞에 <code>pub</code>을 붙이세요.</p>
</li>
<li><p><strong><code>use</code> 키워드</strong>: 어떤 스코프 내에서 <code>use</code> 키워드는 긴 경로의 반복을 줄이기 위한 어떤 아이템으로의 단축경로를 만들어 줍니다. <code>crate::garden::vegetables::Asparagus</code>를 참조할 수 있는 모든 스코프에서 <code>use crate::garden::vegetables::Asparagus;</code>로 단축경로를 만들 수 있으며, 그 이후부터는 스코프에서 이 타입을 사용하려면 <code>Asparagus</code>만 작성해주면 됩니다.  </p>
</li>
</ul>
<p>위의 규칙들을 보여주는 <code>backyard</code>라는 이름의 바이너리 크레이트를 만들어 보았습니다. 디렉터리명 또한 <code>backyard</code>로서, 아래의 파일들과 디렉터리들로 구성되어 있습니다.</p>
<pre><code>backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │   └── vegetables.rs
    ├── garden.rs
    └── main.rs</code></pre><p>지금의 경우 크레이트 루트 파일은 <em>src/main.rs</em>이고, 내용은 아래와 같습니다:</p>
<p>파일명: src/main.rs</p>
<pre><code class="language-rust">use crate::garden::vegetables::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!(&quot;I&#39;m growing {:?}!&quot;, plant);
}</code></pre>
<p><code>pub mod garden;</code> 라인이 컴파일러에게 <em>src/garden.rs</em>에 있는 코드를 포함할 것을 알려주고, <em>src/garden.rs</em>는 아래와 같습니다:</p>
<p>파일명: src/garden.rs</p>
<pre><code class="language-rust">pub mod vegetables;</code></pre>
<p>여기 <code>pub mod vegetables;</code>은 <em>src/garden/vegetables.rs</em>의 코드 또한 포함되어야 함을 의미합니다. 해당 파일의 코드는 아래와 같습니다:</p>
<pre><code class="language-rust">#[derive(Debug)]
pub struct Asparagus {}</code></pre>
<p>이제 위 규칙들의 세부 사항으로 넘어가서 실제로 해보면서 확인합시다!
<br /></p>
<h3 id="모듈-트리-예시">모듈 트리 예시</h3>
<pre><code class="language-rust">mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}</code></pre>
<p>→ 모듈 예시!</p>
<ul>
<li><code>mod</code> 키워드와 모듈 이름(위의 경우 <code>front_of_house</code>)을 지정하여 모듈을 정의합니다.</li>
<li>모듈의 본문은 중괄호로 감싸져 있습니다.</li>
<li><code>hosting</code>, <code>serving</code> 모듈처럼, 모듈 내에는 다른 모듈을 넣을 수 있습니다.</li>
<li>모듈에는 <strong>구조체, 열거형, 상수, 트레이트, 함수(예제 7-1처럼) 등의 아이템 정의</strong> 또한 가질 수 있습니다.</li>
</ul>
<p>위 예시를 트리 구조로 표현하면,</p>
<pre><code>crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment</code></pre><ul>
<li>마치, 파일 디렉터리 구조가 연상된다!</li>
<li>전체 모듈 트리 최상위에 <code>crate</code>라는 모듈이 암묵적으로 위치한다는 점을 기억해 두세요.</li>
<li>앞서 <em>src/main.rs<em>와 *src/lib.rs</em>는 크레이트 루트라고 부른다고 언급했습니다. 이 두 파일이 그런 이름을 갖게 된 이유는 *모듈 트리 (module tree)</em> 라고 불리는 크레이트 모듈 구조에서 최상위에 <code>crate</code>라는 이름을 갖는 일종의 모듈로 형성되기 때문입니다.<br />
### 경로를 사용하여 모듈 트리의 아이템 참조하기

</li>
</ul>
<p>경로는 두 가지 형태가 존재합니다.</p>
<ul>
<li><p><strong><em>절대 경로 (absolute path)</em></strong> 는 크레이트 루트로부터 시작되는 전체 경로이다.
  외부 크레이트로부터의 코드에 대해서는 해당 크레이트 이름으로 절대 경로가 시작되고 현재의 크레이트로부터의 코드에 대해서는 <code>crate</code> 리터럴로부터 시작됩니다.</p>
</li>
<li><p><strong><em>상대 경로 (relative path)</em></strong> 는 현재의 모듈을 시작점으로 하여 <code>self</code>, <code>super</code> 혹은 현재 모듈 내의 식별자를 사용합니다.</p>
</li>
</ul>
<p>절대 경로, 상대 경로 뒤에는 <code>::</code>으로 구분된 식별자가 하나 이상 따라옵니다.</p>
<pre><code class="language-rust">mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
    }
}

pub fn eat_at_restaurant() {
    // 절대 경로
    crate::front_of_house::hosting::add_to_waitlist();

    // 상대 경로
    front_of_house::hosting::add_to_waitlist();
}</code></pre>
<p>→ 이 코드는 에러가 발생합니다! 에러 메시지는 <strong><code>hosting</code> 모듈이 비공개 (private)</strong> 라는 내용입니다. <code>hosting</code> 모듈과 <code>add_to_waitlist</code> 함수의 경로를 정확히 명시했지만, 해당 영역은 비공개 영역이기 때문에 러스트가 접근을 허용하지 않습니다.</p>
<ul>
<li><p><strong><span style="color: red">러스트에서는 (함수, 메서드, 구조체, 열거형, 모듈, 그리고 상수 등) 모든 아이템이 기본적으로 부모 모듈에 대해 비공개입니다.</span></strong> 
  → 함수나 구조체 같은 아이템을 비공개로 하고 싶다면 모듈에 넣으면 됩니다.</p>
</li>
<li><p>부모 모듈 내 아이템은 자식 모듈 내 비공개 아이템을 사용할 수 없지만, 자식 모듈 내 아이템은 부모 모듈 내 아이템을 사용할 수 있습니다.
  이유는, 자식 모듈의 세부 구현은 감싸져서 숨겨져 있지만, 자식 모듈 내에서는 자신이 정의된 컨텍스트를 볼 수 있기 때문입니다.</p>
</li>
<li><p><strong>러스트 모듈 시스템은 내부의 세부 구현을 기본적으로 숨기도록 되어 있습니다.</strong> 이로써, 여러분은 외부 코드의 동작을 망가뜨릴 걱정 없이 수정할 수 있는 코드가 어느 부분인지 알 수 있죠. (당연히 공개되어 있지 않은 부분이겠지?) 그렇지만 러스트에서는 <code>pub</code> 키워드를 사용하여 자식 모듈의 내부 구성 요소를 공개 (public) 함으로써 외부의 상위 모듈로 노출할 방법을 제공합니다.</p>
<br />
### pub 키워드로 경로 노출하기 (공개하기?)

</li>
</ul>
<pre><code class="language-rust">mod front_of_house {
    pub mod hosting {
        fn add_to_waitlist() {}
    }
}

pub fn eat_at_restaurant() {
    // 절대 경로
    crate::front_of_house::hosting::add_to_waitlist();

    // 상대 경로
    front_of_house::hosting::add_to_waitlist();
}</code></pre>
<p>→ 앞의 코드와 비교했을 때, <code>hosting</code> 모듈에 <code>pub</code> 키워드를 추가했습니다. 하지만 이 코드 또한 에러가 발생합니다. 왜 그런 걸까요?</p>
<p><code>hosting</code> 모듈에 <code>pub</code>을 붙여서 모듈이 공개되었으므로, 이제 <code>front_of_house</code> 에 접근할 수 있다면 <code>hosting</code> 에도 접근할 수 있게 되었지만, <code>hosting</code> 모듈의 <strong><em>내용</em></strong>은 여전히 비공개입니다. <strong>모듈을 공개했다고 해서 모듈의 내용까지 공개되지는 않습니다.</strong></p>
<pre><code class="language-rust">mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub fn eat_at_restaurant() {
    // 절대 경로
    crate::front_of_house::hosting::add_to_waitlist();

    // 상대 경로
    front_of_house::hosting::add_to_waitlist();
}</code></pre>
<p>→ 이렇게 <code>add_to_waitlist</code> 함수도 정의에 <code>pub</code> 키워드를 추가해서 공개해야 합니다. 이제서야 우리는 코드를 컴파일할 수 있게 되었습니다!</p>
<p>추가적으로,</p>
<ul>
<li><p>서로 형제 관계에 있을 때는(즉, 같은 모듈 상에 있을 때는) <code>pub</code> 키워드로 공개해주지 않아도 접근할 수 있습니다.</p>
</li>
<li><p><code>pub</code> 키워드로 외부에 공개되었다면, <strong>“해당 대상의 부모에게 접근할 수 있을 때, 해당 대상에게도 접근할 수 있다”</strong> 라고 핵심을 정리할 수 있겠습니다.</p>
<br />
### super로 시작하는 상대 경로
</li>
<li><p>상대 경로에서, <code>super</code> 로 시작하면 현재 모듈 혹은 크레이트 루트 대신 자기 부모 모듈부터 시작되는 경로를 만들 수 있습니다.</p>
<br />
### 구조체, 열거형을 공개하기
</li>
<li><p>구조체 정의에 <code>pub</code>를 쓰면 구조체는 공개되지만, 구조체의 필드는 비공개로 유지됩니다.</p>
</li>
<li><p>반대로, 열거형은 공개로 지정할 경우 모든 배리언트가 공개됩니다. (열거형은 그 배리언트가 공개되지 않는다면 큰 쓸모가 없습니다.)</p>
<br />
### use 키워드로 경로를 스코프 안으로 가져오기
</li>
<li><p><code>use</code> 키워드를 한번 사용하여 어떤 경로의 단축경로 (shortcut) 를 만들 수 있고, 그러면 스코프 안쪽 어디서라도 짧은 이름을 사용할 수 있습니다.</p>
</li>
<li><p>스코프에 <code>use</code> 키워드와 경로를 작성하는 건 파일 시스템에서 심볼릭 링크 (symbolic link) 를 생성하는 것과 유사합니다.</p>
</li>
<li><p><code>use</code> 키워드로 가져온 경우도 다른 경로와 마찬가지로 비공개 규칙이 적용됩니다.</p>
</li>
</ul>
<pre><code class="language-rust">mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}</code></pre>
<p>→ <code>eat_at_restaurant</code> 함수 내에서 <code>add_to_waitlist</code> 함수를 <code>hosting::add_to_waitlist</code> 경로만으로 호출하는 예제입니다.</p>
<ul>
<li><code>use</code>가 사용된 특정한 스코프에서만 단축경로가 만들어진다는 점을 주의하세요. 
  → 다른 스코프에서는 <code>use</code> 구문으로 만들어진 단축 경로가 적용되지 않습니다.</li>
</ul>
<br />
읽어주셔서 감사합니다 🙇‍♂️    


<h2 id="references">References</h2>
<p><a href="https://doc.rust-kr.org/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html">https://doc.rust-kr.org/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - 구조체(struct) 와 메서드(method)]]></title>
            <link>https://velog.io/@h_channni/Rust-%EA%B5%AC%EC%A1%B0%EC%B2%B4struct-%EC%99%80-%EB%A9%94%EC%84%9C%EB%93%9Cmethod</link>
            <guid>https://velog.io/@h_channni/Rust-%EA%B5%AC%EC%A1%B0%EC%B2%B4struct-%EC%99%80-%EB%A9%94%EC%84%9C%EB%93%9Cmethod</guid>
            <pubDate>Tue, 15 Oct 2024 13:05:17 GMT</pubDate>
            <description><![CDATA[<p>구조체에 대한 자세한 사항이 공식문서와 교재에 워낙 잘 설명이 되어 있기 때문에, 해당 내용들을 참고하면서, 제 기준에서 기록과 함께 제대로 체화시켜야 되겠다 싶은 부분들 위주로 정리해볼까 합니다.
<br></p>
<h2 id="구조체-기본-개념">구조체 기본 개념</h2>
<blockquote>
<p>A <strong>struct</strong> (or <strong>structure</strong>) is a custom data type that lets you package together and name multiple related values that make up a meaningful group
<span style="color:gray"> → 고려대학교 ‘시스템 프로그래밍’ 강의자료 중 발췌 </span></p>
</blockquote>
<h3 id="구조체-정의-및-인스턴스-생성">구조체 정의 및 인스턴스 생성</h3>
<pre><code class="language-rust">struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}</code></pre>
<p><code>User</code> 라는 예시 구조체 정의</p>
<pre><code class="language-rust">fn main() {
    let user1 = User {
        active: true,
        username: String::from(&quot;someusername123&quot;),
        email: String::from(&quot;someone@example.com&quot;),
        sign_in_count: 1,
    };
}</code></pre>
<p><code>User</code> 구조체의 인스턴스 생성
<br></p>
<h3 id="필드-초기화-문법">필드 초기화 문법</h3>
<pre><code class="language-rust">fn build_user(email: String, username: String) -&gt; User {
    User {
        active: true,
        username,
        email,
        sign_in_count: 1,
    }
}</code></pre>
<p>위 코드처럼 변수명과 구조체 필드명이 같으면, <code>username: username,</code> 의 형태처럼 두 번 작성할 필요 없이 한 번만 쓰면 OK!
<br></p>
<h3 id="구조체-업데이트-문법-기존-인스턴스를-이용해-새-인스턴스를-만들-때">구조체 업데이트 문법: 기존 인스턴스를 이용해 새 인스턴스를 만들 때</h3>
<pre><code class="language-rust">fn main() {
    // --생략--

    let user2 = User {
        email: String::from(&quot;another@example.com&quot;),
        ..user1
    };
}</code></pre>
<ul>
<li> <code>..</code> 문법은 따로 명시된 필드를 제외한 나머지 필드를 주어진 인스턴스의 필드 값으로 설정합니다.</li>
<li>구조체 업데이트 문법이 대입처럼 <code>=</code> 를 이용한다는 점을 주목해야 합니다. 이로 인해 <code>username</code>처럼 <code>String</code> 데이터로 구조체를 업데이트하는 경우 소유권 이동이 일어날 수 있다는 점을 명심해야 합니다. </li>
<li>다만, <code>Copy</code> 트레이트를 구현한, 스택에만 저장되는 데이터 타입들은 마찬가지로 복사가 일어나므로 소유권에 대한 부분은 크게 신경쓰지 않아도 됩니다.<br>
## 매서드 문법

</li>
</ul>
<p><em>메서드 (method)</em> 는 함수와 유사합니다. <code>fn</code> 키워드와 함수명으로 선언하고, 매개변수와 반환 값을 가지며, 다른 어딘가로부터 호출될 때 실행됩니다. 하지만 메서드는 함수와 달리 구조체 컨텍스트에 정의되고 (열거형이나 트레이트 객체 안에 정의되기도 하며, 이는 각각 <a href="https://doc.rust-kr.org/ch06-00-enums.html">6장</a>, <a href="https://doc.rust-kr.org/ch17-02-trait-objects.html">17장</a>에서 알아보겠습니다), 첫 번째 매개변수가 항상 <code>self</code> 라는 차이점이 있습니다. <code>self</code> 매개변수는 메서드를 호출하고 있는 구조체 인스턴스를 나타냅니다.
<br></p>
<pre><code class="language-rust">#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&amp;self) -&gt; u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!(&quot;The area of rect1 is {} square pixels&quot;, rect1.area());
}

fn area(rectangle: &amp;Rectangle) -&gt; u32 {
    rectangle.height * rectangle.width
}</code></pre>
<p>기존에 따로 함수로 만들었던 <code>area</code> 함수를 <code>Rectangle</code> 구조체의 메서드로 추가해준 코드입니다. 변경사항을 자세히 뜯어보자면..</p>
<ul>
<li><code>impl</code> 블록을 만들어 주었습니다. → <code>area</code> 함수를 블록 내부로 옮기고 함수 시그니처의 첫 번째 매개변수를 <code>self</code>로 고쳐 주었습니다.</li>
<li>함수 호출 시에는 <strong><em>메서드 문법 (method syntax)</em></strong> 을 사용해 <code>Rectangle</code> 인스턴스의 <code>area</code> 메서드를 호출할 수 있습니다. 메서드 문법은 차례대로 인스턴스, 점, 메서드명, 괄호 및 인수로 구성됩니다.</li>
<li><code>area</code> 시그니처를 보면,  <code>rectangle: &amp;Rectangle</code> 대신 <code>&amp;self</code>를 사용했습니다. <code>&amp;self</code>는 실제로는 <code>self: &amp;Self</code>를 줄인 것입니다. <code>impl</code> 블록 내에서 <code>Self</code>는 <code>impl</code> 블록의 대상이 되는 타입의 별칭입니다. 
<font color="red"><strong>→ 즉, <code>self</code>가 파라미터 이름이고, <code>Self</code>가 파라미터 타입이다 !!</strong></font></li>
<li><code>rectangle: &amp;Rectangle</code>에서 그랬던 것처럼, 이 메서드가 <code>Self</code>의 인스턴스를 빌려온다는 것을 나타내기 위해서는 <code>self</code> 축약형 앞에 <code>&amp;</code>를 계속 붙여둘 필요가 있음을 주목하세요. 메서드는 다른 매개변수가 그런 것처럼 <code>self</code>의 소유권을 가져올 수도, 지금처럼 <code>self</code>를 불변으로 빌려올 수도, 가변으로 빌려올 수도 있습니다.<br>
### 함수 대신 메서드 문법을 사용하는 이유?

</li>
</ul>
<p>제가 궁금했던 점은 바로 이 부분이었습니다. 이렇게 구조체의 메서드로 만들어버리면 그냥 따로 함수로 쓰는 것보다 <em>뭔가 더 좋을 것 같긴 한데 …</em> 그게 정확히 무엇일까? 라는 의문이 들었습니다.</p>
<p>교재에서 설명하는 내용은 아래와 같습니다:</p>
<blockquote>
<p>함수 대신 메서드를 사용하는 주된 이유는 메서드 구문을 제공하고 모든 메서드 시그니처 내에서 <code>self</code> 타입을 반복할 필요가 없다는 것 외에도 코드를 더 조직적으로 만들기 위해서입니다. 향후 우리가 제공한 라이브러리를 사용할 사람들이 <code>Rectangle</code>의 기능과 관련된 코드를 라이브러리 곳곳에서 찾아내야 하는 것보다는, 하나의 <code>impl</code> 블록 내에 이 타입의 인스턴스로 할 수 있는 모든 것들을 모아두는 것이죠.</p>
</blockquote>
<p>확실히, 결국 라이브러리의 형태로 코드를 제공해야 한다고 생각했을 때는, 별도의 함수로 뒀을 때보다 메서드로 만들어서 제공하는 것이 이해의 측면에서든, 활용의 측면에서든 훨씬 나을 것이라 짐작됩니다.
<br></p>
<h3 id="연관-함수">연관 함수</h3>
<p><code>impl</code> 블록 내에 구현된 모든 함수를 <em>연관 함수 (associated function)</em> 라고 부르는데, 이는 <code>impl</code> 뒤에 나오는 타입과 모두 연관된 함수이기 때문입니다. 동작하는 데 해당 타입의 인스턴스가 필요하지 않다면 <strong><code>self</code>를 첫 매개변수로 갖지 않는 (따라서 메서드가 아닌) 연관 함수</strong>를 정의할 수도 있습니다. 우리는 이미 <code>String</code> 타입에 정의되어 있는 <code>String::from</code> 함수처럼 이런 종류의 함수를 사용해 봤습니다.</p>
<p>→ 교재에서 ‘연관 함수’라고 소개하는 챕터는 정확히는 <strong>‘(메서드가 아닌) 연관 함수’</strong> 라고 봐야 할 듯 합니다.. 예시를 살펴보겠습니다.</p>
<pre><code class="language-rust">impl Rectangle {
    fn square(size: u32) -&gt; Self {
        Self {
            width: size,
            height: size,
        }
    }
}</code></pre>
<ul>
<li>메서드가 아닌 연관 함수는 구조체의 새 인스턴스를 반환하는 <strong>생성자</strong>로 자주 활용됩니다.</li>
<li>이 함수들은 보통 <code>new</code>라고 명명되는데, <code>new</code>는 이 언어에서 특별한 이름 혹은 키워드가 아닙니다. 
→ 다르게 생각하면, Rust에서도 특정 구조체의 생성자 함수를 정의하고 이름을 <code>new</code>로 지어주면, 다른 언어들과 비슷한 메커니즘으로 활용할 수 있을 것 같습니다!</li>
<li>위 코드는 생성자의 예시로, <code>Rectangle</code>로 정사각형을 만들 때 너비, 높이에 같은 값을 두 번 지정하지 않고 치수 하나를 매개변수로 받아서 해당 치수로 너비와 높이를 설정하는 연관 함수 <code>square</code>를 구현한 것입니다.</li>
<li>반환 타입 및 함수 본문의 <code>Self</code> 키워드는 <code>impl</code> 키워드 뒤에 적혀있는 타입의 별칭으로서, 여기서는 <code>Rectangle</code>이 되겠습니다.</li>
<li><strong>연관 함수를 호출할 땐 <code>let sq = Rectangle::square(3);</code>처럼 구조체 명에 <code>::</code> 구문을 붙여서 호출합니다.</strong>  연관 함수는 구조체의 네임스페이스 안에 있기 때문이죠. <code>::</code> 구문은 <a href="https://doc.rust-kr.org/ch07-02-defining-modules-to-control-scope-and-privacy.html">7장</a>에서 알아볼 모듈에 의해 생성되는 네임스페이스에도 사용됩니다.</li>
</ul>
<p>읽어주셔서 감사합니다 🙇‍♂️
<br></p>
<h2 id="references">References</h2>
<p><a href="https://doc.rust-kr.org/ch05-01-defining-structs.html">https://doc.rust-kr.org/ch05-01-defining-structs.html</a></p>
<p><a href="https://doc.rust-kr.org/ch05-02-example-structs.html">https://doc.rust-kr.org/ch05-02-example-structs.html</a></p>
<p><a href="https://doc.rust-kr.org/ch05-03-method-syntax.html">https://doc.rust-kr.org/ch05-03-method-syntax.html</a></p>
<p>Rust 교재의 한국어 버전을 기반으로 작성한 글임을 다시 한 번 알려드립니다. 🙏</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - 댕글링 참조 (Dangling Reference)]]></title>
            <link>https://velog.io/@h_channni/Rust-%EB%8C%95%EA%B8%80%EB%A7%81-%EC%B0%B8%EC%A1%B0-Dangling-Reference</link>
            <guid>https://velog.io/@h_channni/Rust-%EB%8C%95%EA%B8%80%EB%A7%81-%EC%B0%B8%EC%A1%B0-Dangling-Reference</guid>
            <pubDate>Mon, 14 Oct 2024 06:43:37 GMT</pubDate>
            <description><![CDATA[<p><em>댕글링 포인터 (dangling pointer)</em> 란, 어떤 메모리를 가리키는 포인터가 남아있는 상황에서 일부 메모리를 해제해 버림으로써, 다른 개체가 할당받았을지도 모르는 메모리를 참조하게 된 포인터를 말합니다.
<br>
<a href="https://velog.io/@h_channni/Rust-%EC%B0%B8%EC%A1%B0reference-%EC%99%80-%EB%8C%80%EC%97%ACborrowing">이전 글</a>에서, 작성 도중 떠오른 하나의 질문을 던지고 글을 마무리하였습니다.</p>
<blockquote>
<p>Q. 참조자로 참조를 했는데, 원본 값이 갑자기 사라지면 어떡해 …?
→ A.</p>
</blockquote>
<p>결론부터 말하자면, Rust 프로그램에서는 컴파일러가 이러한 상황을 사전에 방지합니다.
<br></p>
<h2 id="댕글링-포인터">댕글링 포인터</h2>
<blockquote>
<p><strong>Dangling pointers</strong> and <strong>wild pointers</strong> in <a href="https://en.wikipedia.org/wiki/Computer_programming">computer programming</a> are <a href="https://en.wikipedia.org/wiki/Data_pointer">pointers</a> that do not point to a valid object of the appropriate type. These are special cases of <a href="https://en.wikipedia.org/wiki/Memory_safety">memory safety</a> violations. More generally, <strong>dangling references</strong> and <strong>wild references</strong> are <a href="https://en.wikipedia.org/wiki/Reference_(computer_science)">references</a> that do not resolve to a valid destination.
→ 위키백과 ‘Dangling pointer’ 발췌</p>
</blockquote>
<p>댕글링 포인터는 어떤 포인터가 가리키고 있는 메모리가 할당 해제되었으나 여전히 포인터는 그 주소를 가리키고 있는 상황을 말하고, 이 상황은 예측할 수 없는 행동을 발생시키므로 위험합니다. 참고로 이 경우 Linux 혹은 Unix에서는 segmentation fault가, Windows에서는 general protection fault가 발생할 수 있습니다.</p>
<p>포인터가 존재하는 언어에서는 자칫 잘못했다가는 이러한 댕글링 포인터를 만들기 쉽습니다. 다들 그렇듯이 저도 과거에 segmentation fault가 발생해서 잘못된 부분을 찾느라 고생했던 기억이 여럿 있기 때문에, 이를 사전에 방지해준다는 Rust가 더욱 매력적으로 다가오기도 했습니다..ㅋㅋㅋ
<br></p>
<h2 id="rust에서의-댕글링-참조">Rust에서의 댕글링 참조</h2>
<p>러스트에서는 어떤 데이터의 참조자를 만들면, 해당 참조자가 스코프를 벗어나기 전에 데이터가 먼저 스코프를 벗어나는지 컴파일러에서 확인하여 댕글링 참조가 생성되지 않도록 보장합니다.</p>
<p>교재의 예시를 통해 알아보도록 하겠습니다.</p>
<pre><code class="language-rust">fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -&gt; &amp;String {
    let s = String::from(&quot;hello&quot;);

    &amp;s
}</code></pre>
<p>위 코드는 에러가 발생합니다:</p>
<pre><code class="language-bash">$ cargo run
   Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0106]: missing lifetime specifier
 --&gt; src/main.rs:5:16
  |
5 | fn dangle() -&gt; &amp;String {
  |                ^ expected named lifetime parameter
  |
  = help: this function&#39;s return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `&#39;static` lifetime
  |
5 | fn dangle() -&gt; &amp;&#39;static String {
  |                 +++++++

For more information about this error, try `rustc --explain E0106`.
error: could not compile `ownership` due to previous error
</code></pre>
<p>아직 다루지 않은 라이프타임이라는 내용이 에러 메시지에 등장하는데, 라이프타임은 10장에서 다룰 예정이니 일단 무시하도록 하겠습니다. 이 코드가 문제가 되는 이유를 알려주는 핵심 내용은 다음과 같습니다:</p>
<blockquote>
<p>this function&#39;s return type contains a borrowed value, but there is no value for it to be borrowed from.
(해석: 이 함수는 빌린 값을 반환하고 있으나, 빌린 실제 값이 존재하지 않습니다.)</p>
</blockquote>
<p><code>dangle</code> 함수에서 어떤 일이 일어나는지 주석을 통해 알아보도록 하겠습니다:</p>
<pre><code class="language-rust">fn dangle() -&gt; &amp;String { // dangle은 String의 참조자를 반환합니다

    let s = String::from(&quot;hello&quot;); // s는 새로운 String입니다

    &amp;s // String s의 참조자를 반환합니다
} // 여기서 s는 스코프 밖으로 벗어나고 버려집니다. 해당 메모리는 해제됩니다.
  // 위험합니다!</code></pre>
<p><code>s</code>는 <code>dangle</code> 함수 내에서 생성됐기 때문에, 함수가 끝날 때 할당 해제됩니다. 하지만 코드에서는 <code>&amp;s</code>를 반환하려 했고, 이는 유효하지 않은 <code>String</code>을 가리키는 참조자를 반환하는 행위이기 때문에 에러가 발생합니다.</p>
<p>따라서, 이런 경우엔 <code>String</code>을 직접 반환해야 합니다:</p>
<pre><code class="language-rust">fn no_dangle() -&gt; String {
    let s = String::from(&quot;hello&quot;);

    s
}</code></pre>
<p>굳이 참조자를 반환하지 않고, <code>String</code>을 직접 반환해서 소유권을 이동시키는 방식으로 문제를 해결할 수 있습니다. </p>
<p>댕글링 참조가 발생하지 않도록 사전에 방지해주기도 하고, 간단한 해결책 또한 존재하기 때문에 코드를 작성하는 입장에서는 이는 엄청난 이점이라 생각됩니다!</p>
<p>읽어주셔서 감사합니다 🙇‍♂️
<br></p>
<h2 id="references">References</h2>
<p><a href="https://en.wikipedia.org/wiki/Dangling_pointer">https://en.wikipedia.org/wiki/Dangling_pointer</a></p>
<p><a href="https://doc.rust-kr.org/ch04-02-references-and-borrowing.html">https://doc.rust-kr.org/ch04-02-references-and-borrowing.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - 참조(reference) 와 대여(borrowing)]]></title>
            <link>https://velog.io/@h_channni/Rust-%EC%B0%B8%EC%A1%B0reference-%EC%99%80-%EB%8C%80%EC%97%ACborrowing</link>
            <guid>https://velog.io/@h_channni/Rust-%EC%B0%B8%EC%A1%B0reference-%EC%99%80-%EB%8C%80%EC%97%ACborrowing</guid>
            <pubDate>Sun, 13 Oct 2024 13:35:24 GMT</pubDate>
            <description><![CDATA[<p>앞서 Rust의 소유권 개념에 대해 정리하기도 했고, Rust로 과제를 할 때 쓰면서도 확실하게 이해하고 쓰지 못하고 있다는 느낌이 들었던 참조(reference)와 대여(borrowing)에 대한 내용을 정리하면서 확실하게 파악해보려 합니다.</p>
<p>함수에 파라미터를 전달하고, 값을 반환할 때는 대입과 똑같이 소유권의 이동 혹은 복사가 일어난다고 생각하면 이를 이해하는 것 자체에는 큰 문제가 없을 것입니다. 다만, 모든 함수가 매번 소유권을 가졌다가 반납하는 것은 조금 번거롭습니다. </p>
<blockquote>
<p>함수에 넘겨줄 값을 함수 호출 이후에도 쓰고 싶은데, 그렇다고 해서 함수로부터 얻고자 하는 결과에 더해서 이후 다시 쓰고 싶은 변수까지 같이 반환받아야 한다면 본말전도나 다름없죠.</p>
</blockquote>
<p>교재에서 설명하는 위와 같은 경우를 생각해보면 매번 이를 신경쓰는 것은 매우 귀찮은 작업이 될 것 같습니다.</p>
<p>그럼, 함수가 값을 사용할 수 있도록 하되 소유권은 가져가지 않도록 하고 싶다면 어떻게 해야 할까요?</p>
<p>Rust에서는 예제 4-5에서처럼 튜플을 사용하여 여러 값을 반환하는 것이 가능합니다:</p>
<pre><code class="language-rust">fn main() {
    let s1 = String::from(&quot;hello&quot;);

    let (s2, len) = calculate_length(s1);

    println!(&quot;The length of &#39;{}&#39; is {}.&quot;, s2, len);
}

fn calculate_length(s: String) -&gt; (String, usize) {
    let length = s.len(); // len()은 String의 길이를 반환합니다

    (s, length)
}</code></pre>
<p>예제 4.5: 매개변수의 소유권을 되돌려주는 방법<br><br></p>
<p>다만, 이런 방식도 거추장스럽고, 많은 작업량이 수반되는 것은 마찬가지입니다.</p>
<p>다행히도, Rust에는 소유권 이동 없이 값을 사용할 수 있는 <em>참조자 (reference)</em> 라는 기능을 가지고 있습니다.
<br></p>
<h2 id="참조와-대여">참조와 대여</h2>
<p>다음은 참조자를 매개변수로 받도록 구현한 <code>calculate_length</code> 함수의 정의 및 용례입니다.</p>
<pre><code class="language-rust">fn main() {
    let s1 = String::from(&quot;hello&quot;);

    let len = calculate_length(&amp;s1);

    println!(&quot;The length of &#39;{}&#39; is {}.&quot;, s1, len);
}

fn calculate_length(s: &amp;String) -&gt; usize {
    s.len()
}</code></pre>
<p><code>calculate_length</code> 함수에 <code>s1</code> 대신 <code>&amp;s1</code>을 전달하고, 함수 정의에 <code>String</code> 대신 <code>&amp;String</code>을 사용했네요. 이 앰퍼센드(&amp;) 기호가 <em>참조자</em>를 나타내고, 어떤 값의 소유권을 가져오지 않고 해당 값을 참조할 수 있도록 해 줍니다.</p>
<pre><code class="language-rust">    let s1 = String::from(&quot;hello&quot;);

    let len = calculate_length(&amp;s1);</code></pre>
<p>함수 호출부를 보면, <code>s1</code>에 <code>&amp;</code>를 붙인 <code>&amp;s1</code> 구문은 <code>s1</code> 값을 참조하지만 해당 값을 소유하지 않는 참조자를 생성합니다. 값을 소유하지 않으므로 이 참조자가 가리킨 값은 참조자가 사용되지 않을 때까지 버려지지 않습니다.</p>
<p>마찬가지로 함수 시그니처에도 <code>&amp;</code>를 사용하여 매개변수 <code>s</code>가 참조자 타입임을 나타내줍니다. </p>
<pre><code class="language-rust">fn calculate_length(s: &amp;String) -&gt; usize { // s는 String의 참조자입니다
    s.len()
} // 여기서 s가 스코프 밖으로 벗어납니다. 하지만 참조하는 것을 소유하고 있진 않으므로,
  // 버려지지는 않습니다.</code></pre>
<p>변수 <code>s</code>가 유효한 스코프는 여타 함수의 매개변수에 적용되는 스코프와 동일합니다. 하지만 <code>s</code>에는 소유권이 없으므로 <code>s</code>가 더 이상 사용되지 않을 때도 이 참조자가 가리킨 값이 버려지지 않습니다. </p>
<p>함수가 실제 값 대신 참조자를 매개변수로 쓴다면 애초에 소유권이 없으니까 이 소유권을 돌려주기 위한 값 반환도 필요 없어집니다. 거추장스러운 작업이 하나 사라지는 셈이 됩니다. </p>
<p>이처럼 참조자를 만드는 행위를 Rust에서는 <em>대여(borrow)</em> 라고 합니다.
<br></p>
<h2 id="가변-참조자">가변 참조자</h2>
<pre><code class="language-rust">fn main() {
    let s = String::from(&quot;hello&quot;);

    change(&amp;s);
}

fn change(some_string: &amp;String) {
    some_string.push_str(&quot;, world&quot;);
}</code></pre>
<p>이 코드는 컴파일 에러를 발생시킵니다. 변수가 기본적으로 불변성을 지니는 것과 마찬가지로, 참조자 또한 기본적으로 참조하는 값을 수정할 수 없습니다.</p>
<pre><code class="language-bash">$ cargo run
   Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0596]: cannot borrow `*some_string` as mutable, as it is behind a `&amp;` reference
 --&gt; src/main.rs:8:5
  |
7 | fn change(some_string: &amp;String) {
  |                        ------- help: consider changing this to be a mutable reference: `&amp;mut String`
8 |     some_string.push_str(&quot;, world&quot;);
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `some_string` is a `&amp;` reference, so the data it refers to cannot be borrowed as mutable

For more information about this error, try `rustc --explain E0596`.
error: could not compile `ownership` due to previous error</code></pre>
<p><em>가변 참조자 (mutable reference)</em> 를 사용하는 식으로 코드를 살짝만 수정해 주면 에러를 없앨 수 있습니다. </p>
<pre><code class="language-rust">fn main() {
    let mut s = String::from(&quot;hello&quot;);

    change(&amp;mut s);
}

fn change(some_string: &amp;mut String) {
    some_string.push_str(&quot;, world&quot;);
}</code></pre>
<p>에러 메시지 내용에서도 자세히 알려주듯이, <code>mut</code> 키워드를 붙여주면 해결됩니다. </p>
<p>(Rust의 가장 강력한 장점은 컴파일러가 에러 메시지를 매우 친절하게 써 주는 것이라 생각합니다. 그대로 따라하면 손쉽게 문제를 해결할 수 있을 정도로 굉장히 직관적이고, 에러 메시지를 보면서 스스로 잘못한 점을 피드백하고 공부까지 할 수 있을 정도입니다.. Rust의 에러 메시지는 볼 때마다 마치 선생님 같다는 생각이 듭니다. 급 주저리 주저리 ..)</p>
<h3 id="가변-참조자-관련-제약사항">가변 참조자 관련 제약사항</h3>
<p>가변 참조자는 한 가지 큰 제약사항이 있습니다: <strong>어떤 값에 대한 가변 참조자가 있다면, 그 값에 대한 참조자는 더 이상 만들 수 없습니다.</strong> 아래의 코드는 <code>s</code>에 대한 두 개의 가변 참조자 생성을 시도하는 코드로, 작동하지 않습니다:</p>
<pre><code class="language-rust">    let mut s = String::from(&quot;hello&quot;);

    let r1 = &amp;mut s;
    let r2 = &amp;mut s;

    println!(&quot;{}, {}&quot;, r1, r2);</code></pre>
<p>에러는 다음과 같습니다:</p>
<pre><code class="language-bash">$ cargo run
   Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0499]: cannot borrow `s` as mutable more than once at a time
 --&gt; src/main.rs:5:14
  |
4 |     let r1 = &amp;mut s;
  |              ------ first mutable borrow occurs here
5 |     let r2 = &amp;mut s;
  |              ^^^^^^ second mutable borrow occurs here
6 |
7 |     println!(&quot;{}, {}&quot;, r1, r2);
  |                        -- first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `ownership` due to previous error
</code></pre>
<p>대부분의 언어들이 언제든 값 변경을 허용하고 있기 때문에, Rust를 처음 사용할 경우에는 이러한 제약이 장애물처럼 다가올 수 있습니다. 하지만, 이 제약 덕분에 러스트에서는 컴파일 타임에 <em>데이터 경합 (data race)</em> 을 방지할 수 있습니다. </p>
<p>데이터 경합이란 다음 세 가지 상황이 겹칠 때 일어나는 특정한 경합 조건 (race condition) 입니다:</p>
<ul>
<li>둘 이상의 포인터가 동시에 같은 데이터에 접근</li>
<li>포인터 중 하나 이상이 데이터에 쓰기 작업을 시행</li>
<li>데이터 접근 동기화 메커니즘이 없음<br>

</li>
</ul>
<p>가변 참조자와 불변 참조자를 혼용할 때도 유사한 규칙이 적용됩니다. 다음 코드는 컴파일 에러가 발생합니다:</p>
<pre><code class="language-rust">    let mut s = String::from(&quot;hello&quot;);

    let r1 = &amp;s; // 문제없음
    let r2 = &amp;s; // 문제없음
    let r3 = &amp;mut s; // 큰 문제

    println!(&quot;{}, {}, and {}&quot;, r1, r2, r3);</code></pre>
<p>에러는 다음과 같습니다:</p>
<pre><code class="language-bash">$ cargo run
   Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
 --&gt; src/main.rs:6:14
  |
4 |     let r1 = &amp;s; // no problem
  |              -- immutable borrow occurs here
5 |     let r2 = &amp;s; // no problem
6 |     let r3 = &amp;mut s; // BIG PROBLEM
  |              ^^^^^^ mutable borrow occurs here
7 |
8 |     println!(&quot;{}, {}, and {}&quot;, r1, r2, r3);
  |                                -- immutable borrow later used here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `ownership` due to previous error
</code></pre>
<p>어떤 값에 대한 불변 참조자가 있는 동안 같은 값의 가변 참조자를 만드는 것 <em>또한</em> 불가능합니다.</p>
<p>반면 데이터를 읽기만 하는 기능으로는 다른 쪽에서 값을 읽는 기능에 영향을 주지 않으므로, 여러 개의 불변 참조자를 만드는 것은 가능합니다.</p>
<p>요악하자면, 아래와 같습니다:</p>
<ul>
<li>어떤 값에 <strong>가변 참조자</strong> 존재<ul>
<li>해당 값에 <strong>가변 참조자</strong> 생성 불가능</li>
<li>해당 값에 <strong>불변 참조자</strong> 또한 생성 불가능</li>
</ul>
</li>
<li>어떤 값에 <strong>불변 참조자</strong> 존재<ul>
<li>해당 값에 <strong>가변 참조자</strong> 생성 불가능</li>
<li>해당 값에 <strong>불변 참조자</strong> 생성 가능 (여러개 또한 가능)</li>
</ul>
</li>
</ul>
<h3 id="참조자의-스코프">참조자의 스코프</h3>
<p>참조자는 <strong>정의된 지점</strong>부터 시작하여 <strong>해당 참조자가 <em>마지막으로 사용된</em> 부분까지</strong> 유효합니다. 즉, 다음 코드는 불변 참조자가 마지막으로 사용되는 <code>println!</code> 이후에 가변 참조자의 정의가 있으므로 컴파일 에러가 발생하지 않습니다.</p>
<pre><code class="language-rust">    let mut s = String::from(&quot;hello&quot;);

    let r1 = &amp;s; // 문제없음
    let r2 = &amp;s; // 문제없음
    println!(&quot;{} and {}&quot;, r1, r2);
    // 이 지점 이후로 변수 r1과 r2는 사용되지 않습니다

    let r3 = &amp;mut s; // 문제없음
    println!(&quot;{}&quot;, r3);</code></pre>
<p>불변 참조자 <code>r1</code>, <code>r2</code>의 스코프는 자신들이 마지막으로 사용된 <code>println!</code> 이후로 종료되고, 해당 <code>println!</code>은 가변 참조자 <code>r3</code>가 생성되기 전이니 서로 스코프가 겹치지 않아서 이 코드는 문제가 없는 것이죠: 컴파일러는 이 참조자가 어떤 지점 이후로 스코프 끝까지 사용되지 않음을 알 수 있습니다.
<img src="https://velog.velcdn.com/images/h_channni/post/be580002-9df5-4bee-96aa-604603c99116/image.png" alt="시프 강의자료 가변참조자">
강의자료에서 손글씨로 필기한 내용 중, scope를 표시한 부분을 한번 유심히 확인해보면 좋을 것 같습니다! (예시코드는 똑같은 코드입니다~)</p>
<p>스코프가 겹치지 않도록 하는 또 하나의 방법으로, 중괄호로 새로운 스코프를 만들어 가변 참조자를 여러 개 만들면서 <em>동시에</em> 존재하는 상황을 회피하는 방법이 있습니다:</p>
<pre><code class="language-rust">    let mut s = String::from(&quot;hello&quot;);

    {
        let r1 = &amp;mut s;
    } // 여기서 r1이 스코프 밖으로 벗어나며, 따라서 아무 문제없이 새 참조자를 만들 수 있습니다.

    let r2 = &amp;mut s;</code></pre>
<br>

<h3 id="참조자-여러개를-만들-수-있는지에-대한-규칙-요약">참조자 여러개를 만들 수 있는지에 대한 규칙 요약:</h3>
<ol>
<li>어떤 값에 대한 가변 참조자가 있다면, 그 값에 대한 참조자는 더 이상 만들 수 없다.</li>
<li>어떤 값에 대한 불변 참조자가 <strong>있는 동안</strong>, 같은 값의 가변 참조자를 만드는 것 또한 불가능하다.</li>
<li>여러 개의 불변 참조자를 만드는 것은 가능하다.</li>
<li>단, 참조자들의 스코프가 겹치지 않는다면 컴파일 에러가 발생하지 않는다. → 참조자의 스코프는 정의된 지점부터 마지막으로 사용된 부분까지!!<br>

</li>
</ol>
<h2 id="떠오른-질문">떠오른 질문</h2>
<p>참조와 대여에 대한 내용을 정리하면서, 이런 질문이 떠올랐습니다.</p>
<p>Q. 참조자로 참조를 했는데, 원본 값이 갑자기 사라지면 어떡해 …?
→ A. </p>
<p>이 질문에 대한 답은 <em>‘댕글링 참조’</em>라는 내용으로 친절하게 설명이 되어 있는데, 내용이 너무 길어지니 다음 글로 나누도록 하겠습니다 .!!</p>
<p>읽어주셔서 감사합니다 🙇‍♂️
<br></p>
<h2 id="references">References</h2>
<p><a href="https://doc.rust-kr.org/ch04-02-references-and-borrowing.html">https://doc.rust-kr.org/ch04-02-references-and-borrowing.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Rust - Ownership (소유권) 정리]]></title>
            <link>https://velog.io/@h_channni/Rust-Ownership-%EC%86%8C%EC%9C%A0%EA%B6%8C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@h_channni/Rust-Ownership-%EC%86%8C%EC%9C%A0%EA%B6%8C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 13 Oct 2024 11:36:58 GMT</pubDate>
            <description><![CDATA[<p>Rust만의 메모리 관리 규칙인 Ownership(소유권) 개념에 대해 정리해 보려 합니다.</p>
<h2 id="소유권이란-무엇인가">소유권이란 무엇인가</h2>
<p>소유권은 러스트 프로그램의 메모리 관리법을 지배하는 규칙 모음입니다.</p>
<blockquote>
<p>모든 프로그램은 작동하는 동안 컴퓨터의 메모리 사용 방법을 관리해야 합니다. 몇몇 언어는 가비지 컬렉션으로 프로그램에서 더 이상 사용하지 않는 메모리를 정기적으로 찾는 방식을 채택했고, 다른 언어는 프로그래머가 직접 명시적으로 메모리를 할당하고 해제하는 방식을 택했습니다. 이때 러스트는 제3의 방식을 택했습니다: 소유권 (ownership) 이라는 시스템을 만들고, 컴파일러가 컴파일 중에 검사할 여러 규칙을 정해 메모리를 관리하는 방식이지요. </p>
</blockquote>
<p>→ The Rust Programming Language 교재 번역본에 나와 있는 소유권에 대한 설명입니다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/73f85478-d458-405e-8dc5-12458fe25a6a/image.png" alt="시프 강의 소유권 설명">
→ 현재 수강중인 ‘시스템 프로그래밍’ 과목의 Lec03 - Memory Ownership 강의자료 발췌<br>즉, 앞으로 알아볼 ‘소유권’이라는 개념은 Rust 프로그램이 메모리를 관리하는 rule들의 모음이며, runtime cost에 영향을 미치지 않는 zero-cost abstraction에 해당합니다.</p>
<h2 id="소유권-규칙">소유권 규칙</h2>
<p>소유권 규칙부터 알아보겠습니다. 앞으로 나올 내용을 보는 동안 다음 규칙을 명심하세요:</p>
<ul>
<li>러스트에서, 각각의 값은 <em>소유자 (owner)</em> 가 정해져 있습니다.</li>
<li>한 값의 소유자는 동시에 여럿 존재할 수 없습니다.</li>
<li>소유자가 스코프 밖으로 벗어날 때, 값은 버려집니다 (dropped).  <br>

</li>
</ul>
<h3 id="string-타입">String 타입</h3>
<p>소유권에 대해 더 자세히 이해하기 위해, 교재에서는 힙에 데이터를 저장하는 <code>String</code> 타입을 활용하고 있습니다.</p>
<p>문자열 리터럴은 쓰기 편하지만, 불변성을 지니고 있고(immutable), 사용자 입력을 받는 등 컴파일 타임에 값을 알 수 없는 경우에는 사용할 수 없습니다. 반면, <code>String</code> 타입은 힙에 할당된 데이터를 다루기 때문에, 컴파일 타임에 크기를 알 수 없는 텍스트도 저장할 수 있습니다. </p>
<p><code>String</code> 타입은 다음과 같이 <code>from</code> 함수와 문자열 리터럴을 이용해 생성 가능합니다.</p>
<pre><code class="language-rust">let s = String::from(&quot;hello&quot;);</code></pre>
<h3 id="메모리와-할당">메모리와 할당</h3>
<p><code>String</code> 타입은 힙에 메모리를 할당하는 방식을 사용하기 때문에 텍스트 내용 및 크기를 변경할 수 있습니다. 하지만 이는 다음을 의미하기도 합니다:</p>
<ul>
<li>실행 중 메모리 할당자로부터 메모리를 요청해야 합니다.</li>
<li><code>String</code> 사용을 마쳤을 때 메모리를 해제할 (즉, 할당자에게 메모리를 반납할) 방법이 필요합니다.</li>
</ul>
<p>첫번째는 앞에서 본 <code>String::from</code>을 호출하면서 해결했습니다. 그렇다면 두 번째는 어떨까요?</p>
<p>먼저 기존의 언어들에서 메모리를 해제하던 방식에 대해 알아보겠습니다.</p>
<ul>
<li><em>가비지 컬렉터 (garbage collector, GC)</em> 를 갖는 언어에서는 GC가 사용하지 않는 메모리를 찾아 없애주므로 프로그래머가 신경 쓸 필요 없습니다.</li>
<li>GC가 없는 대부분의 언어에서는 할당받은 메모리가 필요 없어지는 지점을 프로그래머가 직접 찾아 메모리 해제 코드를 작성해야 합니다. → 이 작업은 역사적으로 어려운 프로그래밍 문제였습니다.<ul>
<li>프로그래머가 놓친 부분이 있다면 메모리 낭비가 발생하고, 메모리 해제 시점을 너무 일찍 잡으면 유효하지 않은 변수가 생깁니다.</li>
<li>두 번 해제할 경우도 마찬가지로 버그가 발생합니다. 따라서 <code>allocate</code> (할당) 과 <code>free</code> (해제) 가 하나씩 짝짓도록 만들어야 합니다.</li>
</ul>
</li>
</ul>
<p>Rust에서는 이 문제를 <strong>변수가 자신이 소속된 스코프를 벗어나는 순간 자동으로 메모리를 해제하는 방식</strong>으로 해결했습니다.</p>
<pre><code class="language-rust">    {
        let s = String::from(&quot;hello&quot;); // s는 이 지점부터 유효합니다

        // s를 가지고 무언가 합니다
    }                                  // 이 스코프가 종료되었고, s는 더 이상
                                       // 유효하지 않습니다.</code></pre>
<p>위 코드에는 <code>String</code>에서 사용한 메모리를 자연스럽게 해제하는 지점이 있습니다.</p>
<h3 id="변수와-데이터-간-상호작용-방식-이동">변수와 데이터 간 상호작용 방식: 이동</h3>
<p>Rust에서는 동일한 데이터에 여러 변수가 서로 다른 방식으로 상호작용할 수 있습니다. 먼저, 첫 번째 케이스입니다.</p>
<pre><code class="language-rust">    let x = 5;
    let y = x;</code></pre>
<p>‘<code>5</code>를 <code>x</code>에 바인딩하고, <code>x</code> 값의 복사본을 만들어 <code>y</code>에 바인딩하시오’ 그럼 <code>x</code>, <code>y</code> 두 변수가 생길 겁니다. 각각의 값은 <code>5</code>가 되겠죠. 실제로도 이와 같은데, 정수형 값은 크기가 정해진 단순한 값이기 때문입니다. 이는 다시 말해, 두 <code>5</code> 값은 스택에 푸시된다는 뜻입니다.</p>
<p>앞선 예제를 String으로 바꾼 두 번째 케이스입니다.</p>
<pre><code class="language-rust">    let s1 = String::from(&quot;hello&quot;);
    let s2 = s1;</code></pre>
<p>이 코드는 전혀 다른 방식으로 동작합니다.</p>
<p><img src="https://velog.velcdn.com/images/h_channni/post/88d63651-4fd5-44a9-bff9-5040020d4677/image.png" alt="시프 강의자료 move 설명">
마찬가지로 ‘시스템 프로그래밍’ 강의 자료 중 위 코드의 설명에 대한 그림을 캡처한 사진입니다.</p>
<p><code>s2</code>에 <code>s1</code>을 대입하면, <code>String</code> 데이터가 복사됩니다. 여기서 말하는 데이터는 스택에 있는 포인터, 길이, 용량 값을 말하며, 포인터가 가리키는 힙 영역의 데이터는 복사되지 않습니다.</p>
<p>다만, 이 경우 <code>s1</code>과 <code>s2</code>가 스코프 밖으로 벗어날 때 각각 메모리를 해제하게 되면 <em>중복 해제 (double free)</em> 에러가 발생할 겁니다. 또한, Rust 프로그램 상에서는 앞서 말했던 <strong>소유권 규칙 2번(&#39;한 값의 소유자는 동시에 여럿 존재할 수 없습니다.&#39;)</strong>에 위배되는 것이기도 합니다.</p>
<p>메모리 안정성을 보장하기 위해서, Rust는 <code>let s2 = s1;</code> 라인 뒤로는 <code>s1</code>이 더 이상 유효하지 않다고 판단합니다. 이로써 Rust는 <code>s1</code>이 스코프를 벗어나더라도 아무것도 해제할 필요가 없어집니다. <code>s2</code>가 만들어진 이후에 <code>s1</code>을 사용하는 경우 어떤 일이 생기는지 확인해 보면, 작동하지 않음을 알 수 있습니다.</p>
<p>이 개념은 다른 프로그래밍 언어에서 말하는 <em>얕은 복사(shallow copy)</em>와 유사하지만, Rust에서는 기존의 변수를 무효화하기 때문에 이를 <em>이동(move)</em>이라 합니다.</p>
<h3 id="변수와-데이터-간-상호작용-방식-클론">변수와 데이터 간 상호작용 방식: 클론</h3>
<p><code>String</code>의 힙 데이터까지 깊이 복사하고 싶을 땐 <code>clone</code>이라는 공용 메서드를 사용할 수 있습니다. (메서드 문법은 5장에서 다룰 예정이지만, 메서드라는 개념은 대부분의 프로그래밍 언어가 갖는 특성이기 때문에 이미 다뤄보셨을 겁니다.)</p>
<pre><code class="language-rust">    let s1 = String::from(&quot;hello&quot;);
    let s2 = s1.clone();

    println!(&quot;s1 = {}, s2 = {}&quot;, s1, s2);</code></pre>
<h3 id="스택에만-저장되는-데이터-복사">스택에만 저장되는 데이터: 복사</h3>
<pre><code class="language-rust">    let x = 5;
    let y = x;

    println!(&quot;x = {}, y = {}&quot;, x, y);</code></pre>
<p>위 코드는 정상적으로 동작합니다.</p>
<p>이유는 정수형 등 컴파일 타임에 크기가 고정되는 타입은 모두 스택에 저장되기 때문입니다. 스택에 저장되니, 복사본을 빠르게 만들 수 있고, 따라서 굳이 <code>y</code>를 생성하고 나면 <code>x</code>를 무효화할 필요가 없습니다. 다시 말해 이런 경우엔 깊은 복사와 얕은 복사 간에 차이가 없습니다. 여기선 <code>clone</code>을 호출해도 얕은 복사와 차이가 없으니 생략해도 상관없죠.
<br></p>
<h2 id="소유권과-함수">소유권과 함수</h2>
<p>함수에 파라미터를 전달하는 것은 변수에 값을 대입할 때와 유사합니다. 함수에 변수를 전달하면 대입 연산과 마찬가지로 이동 혹은 복사가 일어나게 됩니다.</p>
<pre><code class="language-rust">fn main() {
    let s = String::from(&quot;hello&quot;);  // s가 스코프 안으로 들어옵니다

    takes_ownership(s);             // s의 값이 함수로 이동됩니다...
                                    // ... 따라서 여기서는 더 이상 유효하지 않습니다

    let x = 5;                      // x가 스코프 안으로 들어옵니다

    makes_copy(x);                  // x가 함수로 이동될 것입니다만,
                                    // i32는 Copy이므로 앞으로 계속 x를
                                    // 사용해도 좋습니다

} // 여기서 x가 스코프 밖으로 벗어나고 s도 그렇게 됩니다. 그러나 s의 값이 이동되었으므로
  // 별다른 일이 발생하지 않습니다.

fn takes_ownership(some_string: String) { // some_string이 스코프 안으로 들어옵니다
    println!(&quot;{}&quot;, some_string);
} // 여기서 some_string이 스코프 밖으로 벗어나고 `drop`이 호출됩니다.
  // 메모리가 해제됩니다.

fn makes_copy(some_integer: i32) { // some_integer가 스코프 안으로 들어옵니다
    println!(&quot;{}&quot;, some_integer);
} // 여기서 some_integer가 스코프 밖으로 벗어납니다. 별다른 일이 발생하지 않습니다.</code></pre>
<p>위 코드에서 주석으로 표시된 설명을 참고해 보면 도움이 될 것 같습니다. <code>takes_ownership</code> 함수를 호출한 이후 <code>s</code>를 사용하려 하면, 이미 값의 이동이 일어났으므로 컴파일 에러가 발생합니다.</p>
<pre><code class="language-rust">fn main() {
    let s1 = gives_ownership();         // gives_ownership이 자신의 반환 값을 s1로
                                        // 이동시킵니다

    let s2 = String::from(&quot;hello&quot;);     // s2가 스코프 안으로 들어옵니다

    let s3 = takes_and_gives_back(s2);  // s2는 takes_and_gives_back로 이동되는데,
                                        // 이 함수 또한 자신의 반환 값을 s3로
                                        // 이동시킵니다
} // 여기서 s3가 스코프 밖으로 벗어나면서 버려집니다. s2는 이동되어서 아무 일도
  // 일어나지 않습니다. s1은 스코프 밖으로 벗어나고 버려집니다.

fn gives_ownership() -&gt; String {             // gives_ownership은 자신의 반환 값을
                                             // 자신의 호출자 함수로 이동시킬
                                             // 것입니다

    let some_string = String::from(&quot;yours&quot;); // some_string이 스코프 안으로 들어옵니다

    some_string                              // some_string이 반환되고
                                             // 호출자 함수 쪽으로
                                             // 이동합니다
}

// 이 함수는 String을 취하고 같은 것을 반환합니다
fn takes_and_gives_back(a_string: String) -&gt; String { // a_string이 스코프 안으로
                                                      // 들어옵니다

    a_string  // a_string이 반환되고 호출자 함수 쪽으로 이동합니다
}</code></pre>
<p>위 코드에서는 주석으로 함수에서 값이 반환될 때 값의 이동에 대해 설명하고 있습니다. 
상황은 다양할지라도, 변수의 소유권 규칙은 언제나 동일합니다. </p>
<p>어떤 값을 다른 변수에 대입하면 값이 이동하고, 힙에 데이터를 갖는 변수가 스코프를 벗어나면, 사전에 해당 데이터가 이동하여 소유권이 다른 변수에 이동되지 않은 이상 <code>drop</code> 에 의해 데이터가 제거됩니다. 이 본질을 기억하면, 아무리 상황이 복잡하더라도 소유권 변화에 대한 흐름을 금방 파악할 수 있을 것입니다.</p>
<h2 id="references">References</h2>
<p><a href="https://doc.rust-kr.org/ch04-01-what-is-ownership.html">https://doc.rust-kr.org/ch04-01-what-is-ownership.html</a></p>
]]></description>
        </item>
    </channel>
</rss>