728x90
반응형

Docker는 Linux에 직접 설치해서 사용하는게 최선의 방법이지만 대부분 개발자들이 Windows나 MacOs를 사용하고 있으므로 Windows 사용자에 타게팅을 해서 설명하겠다. (아쉽게도 MacOS가 없다 ㅠ.ㅠ)

Docker는 역사가 아주 짧진 않기 때문에 다양한 기능들이 추가되었다. 더 고급기능을 구사하려면 세부적인 기술들을 학습해야 하겠지만 그건 전문적으로 사용하기 위한 사람들을 위한 거니 전문 책을 하나 사서 기술을 익혀보도록 하자.

Docker에 대한 글은 아주 많다. Docker 설치부터 이미지 pull 해서 간단하게 사용하는건 크게 어렵지 않다.

예전부터 Docker를 사용해보려고 했는데 항상 걸리는 부분이 있었다. 각 컨테이너들에 어떻게 접속해야 하는거냐 라는건데 이게 생각보다 쉽진 않았다.(지금이야 어렵지 않은 부분이지만..) 차근차근 학습했으면 어렵지 않은 부분인데 다급하게 뭔가를 하려고 하다보니 매번 막혀서 포기를 하곤 했다.

다시 말하지만 이 글은 Docker를 거창하게 사용하기 위한게 아니다.

단순히 필요한 컨테이너들을 만들어 어떻게 조합해서 쓰는지 까지만 쓰도록 하겠다. 나머지 고급기술들은 책사서 보는걸 추천한다. 

1. Docker 설치 하기 위해 확인할 사항

- 작업 PC에서 가상화가 활성화 되어있는지 확인

Ctrl + Shift + Esc 를 눌러 작업관리자를 연다.

성능 탭을 클릭하고 가상화 여부를 확인한다. (Window 11 기준이지만 Windows 10도 유사함)

- Hyper-V가 설치되어 있는지 확인

특수키 Window 를 클릭하고 (키보드에 윈도우 창이 그려진 (Ctrl 과 Alt 사이에 보통 있음) 키) 다음을 입력한다.

Windows 기능 켜기/끄기

보통 초기에는 Hyper-V가 설치되어 있지 않을 것이다.

클릭하여 설치를 진행한다.

두 가지가 확인되었다면 다음 단계를 진행한다.

2.Docker 설치

https://www.docker.com/

 

Docker: Accelerated Container Application Development

Docker is a platform designed to help developers build, share, and run container applications. We handle the tedious setup, so you can focus on the code.

www.docker.com

여기서 Download for Windows를 클릭하여 Windows 용을 설치한다.

그냥 기본 옵셥으로 설치해준다.

필요하면 Docker 계정을 생성하고 로그인 해준다.

3. Image Pull 하기

트레이에 있는 Docker 아이콘을 클릭하여 Docker UI를 실행하여 상단에 검색 부분을 클릭한다.

일단 테스트로 ubuntu를 검색하여 Pull 받는다. (ubuntu official image 이다)

그럼 내 컴퓨터에 Local Images를 내려 받는다. 

UI에서 container 생성까지 할 수 있지만 이상하게 생성된 container가 정상적으로 실행되지 않는다. 

아직 원인을 확인하지 못했고 Command Line 창에서 처리가 가능하니 문제점 확인은 추후에 하도록 하자.

4. Ubuntu Container 생성하기 (CMD)

Command Line 창을 실행한다. (윈도우키 + R 클릭 후 cmd 입력 후 엔터)

docker images 를 실행하면 앞에서 Pull 해온 ubuntu 이미지가 조회된다.

docker run -it --name [컨테이너명] [이미지]    ( [ ] 대괄호 기호는 입력하지 않고 명칭만 입력)

그럼 ubuntu image를 기반으로 container를 생성하고 root 계정으로 로그인된다.

C:\> docker run -it --name ubuntu_test3 ubuntu
root@8ca39efcf85c:/#

이제 리눅스 명령어를 사용하여 정상적으로 실행되는지 확인해 본다.

아주 기본적인 ubuntu 만 설치되었기 때문에 일반적인 명령어들이 작동하지 않을 수 있다. (추후에 설치)

 

이렇게 Docker를 설치하여 필요한 이미지를 Pulling 받고 container를 생성 후 실행하는 작업까지 빠르게 진행해 보았다.

여기까지 정상적으로 잘 따라왔다면 오늘은 성공이다. 

내일은 생성된 container를 어떻게 활용해야 할지에 대해 설명해 보겠다.

 

- End

728x90
728x90
반응형

AI 기술이 갑자기 관심을 받으면서 핫해진지 조금 되었다.

이제 좀 열기가 식은것 같은 느낌인데 절대 사그라들지 않을 기술 분야이다.

소설이나 영화에서나 나오던 망상에 가깝던 기술들이 세상에 어떻게 적용될지 단맛을 봤기 때문이다.

앞으로 나타날 여러가지 기술들 가상현실, 메타버스, 블록체인, 우주여행, 자율주행, 로봇, 4차혁명, 등등의 기술들에 반드시 적용될 기술이며 앞으로의 기술발전에 정말 어마어마한 역할을 하게 될것이다. 아마 몇년전만 해도 이런 기술들에 대해 얘기하면 이상한 사람 취급받기 쉽상이었을텐데 갑자기 발표한 Chat GPT 같은 기술들을 공개하면서 대중들의 생각을 완전히 바꿔놓은것 같다. 

이제 마지막 기술스택이라고 생각하면서 AI 쪽으로 접근해보려고 한다. 기술학습에 욕심이 많아서 이것저것 손을 많이 대어봤는데 너무 빠른 기술 발전에 늘 갈아타기를 했던것 같다. 넓고 깊은 T 자형 지식을 만들었어야 했는데 넓기만하고 깊이가 없는 개발자가 되어 버린 느낌이어서 많이 아쉽다. 깊이 있는 학습을 위해 한가지만 파도록 할 생각이다.

꽤나 긴 여행이 될것같다.

공부 하다가 흔들리면 이 글을 읽어보고 마음을 다잡을 수 있었으면 좋겠다.

시작해보자.

 

일단 Python을 기본으로 좀 더 깊이 있게 학습을 하게 될꺼고 Mojo를 집중적으로 파보겠다.

- Mojo
- BUN
- Svelt

이렇게 학습을 시작하고 추후 Zig 나  Rust도 배워보고 싶다.

728x90
728x90
반응형

 

 

 

소프트웨어에는 사실 의미있는 것들이 거의 없다.

 

만일 그런 게 있다고 할지라도, 유일한 성공 척도는

 

고객들이 뭐가 문제인지 몰라 갈팡질팡하는 걸 도와주었냐 하는 것이다.

 

 

- Jeff Atwood 

StackOverFlow의 창립자

 

728x90
728x90
반응형

Pynecone

Pynecone 소개 (피네콘)

피네콘은 웹앱을 만들고 배포하기 위한 풀스택 프레임워크 이다.

(한국분들이 파인콘이라고 읽는데 피네콘이 맞는 발음이다)

댓글에 파인콘이라고 읽기도 한다고 하셔서 검색해보니 파인콘이라고 발음을 하네요.

일단 파인콘이라고 발음하는걸로 수정하겠습니다. 감사합니다.

 

Pynecone 풀스택 프레임워크의 장점

  • Pure Python (파이썬만 사용) : 다른 언어를 학습하지 않고 순수 파이썬 언어로 개발 가능
  • Easy to Learn (배우기 쉬움) : 별도의 웹개발 경험이 없이도 빠르게 웹앱을 개발 가능
  • Full Flexibility (유연함) : 작은 데이터 사이언스 앱 부터 대규모 다중 페이지 웹사이트 까지 구축이 가능
  • Batteries included (필요한 도구 모두 제공) : 앱개발에 필요한 프론트엔드,백엔드, 배포를 모두 처리 가능

 

 

Pynecone 설치

  • Python 3.7 이상
  • NodeJS 12.22.0 이상

 

 

가상 환경 (필요 시 설치)

 

 

개발환경 설치

pip install pynecone-io

많은것을 설치하는데 시간이 좀 걸린다. 멈춰있다고 종료하지 말고 충분히 기다리자.

 

프로젝트 생성

mkdir hello

cd hello

pc init

 

 

앱 실행

pc run

디버깅모드 실행 하려면

pc run --log-level debug

pc 는 pynecone 의 약어

웹서버가 구동되고 나면 웹브라우저를 실행 후 http://localhost:3000 접속

port는 default로 3000으로 설정되어 있으나 pcconfig.py에 port 를 변경 설정이 가능하다.

app 명칭은 hello 이다.

내부적으로 sqlite db 를 사용하는 것도 확인할 수 있다.

javascript  라이브러리 관리 모듈로 bun 을 사용하는것도 확인할 수 있다.

 

 

프로젝트 구조

 

.web 디렉토리

python으로 작성된 코드를 compile 하게되면 nextJS 형태의 소스로 전환해주어 .web 폴더에 생성해 준다.

nextJS 는 React 기반의 프레임워크이다.

개발자는 이 디렉토리의 파일들을 건들 필요가 없지만 디버깅시 유용하게 사용할 수 있다.

 

 

Assets 디렉토리

대부분 그렇듯이 Assets 디렉토리에는 정적인 데이터들이 보관된다. 예를 들면 이미지 파일, 폰트 같은 것들이 정적인 데이터들이다. 컴파일이 되면 .web/public 폴더에 저장 된다.

 

 

Config 파일

 

 

간략하게 Pynecone를 개발하기 위한 설치 방법과 디렉토리 구조를 확인해 봤다.

다음에는 프로젝트에서 사용되는 컴포넌트들에 대해서 작성해보겠다.

 

 

이 글은 Pynecone 공식홈페이지 Learn 문서를 번역/수정 했다.

https://pynecone.io/docs/getting-started/introduction

 

728x90
728x90
반응형

최근에 업데이트된 Flutter 업데이트가 핫한것 같다. 

 

이번 Flutter 3.7 업데이트는 인상적인것들이 좀 있는것 같은데 앞으로의 모바일앱은 Dart 기반 Flutter로 만들어 보기로 했다.

 

그래서 Dart의 기본적인 문법을 소개하고 꾸준히 문법과 샘플코드들을 업데이트 하면서 기록을 진행 하도록 하겠다.

 

https://dart.dev/samples

 

GitHub - dart-lang/samples: A collection of Dart code samples by Dart DevRel

A collection of Dart code samples by Dart DevRel. Contribute to dart-lang/samples development by creating an account on GitHub.

github.com

 

Dart 언어의 가장 기본적인 문법을 간단한 샘플로 나열해 놓은 Sample 페이지이다.

 

Dart는 2011년 10월에 구글에서 처음 공개되었는데 기본적으로는 C언어의 문법을 기반으로 C#, Javascript, Java 같은 기능적인 부분을 추가하여 기존세대의 언어들의 장점과 최근 주류를 이루고 있는 함수형 프로그래밍 언어의 장점을 뽑아서 만들어놓은것 같다. 

코드를 보면 지금껏 C#이나 Java, Javascript 를 써왔던 내가 전혀 이질감이 느껴지지 않은 문법 구조를 가지고 있다.

 

 

그리고 앞으로는 WebAssembly 까지 지원할 예정이므로 Dart를 바이너리 수준의 속도까지 아우를 수 있을 것 같다.

이렇게 새로운 언어가 걷기를 거쳐서 뛰기 시작할 준비가 되었는데 예전엔 너무 많은 좋은 언어들이 경쟁을 하고 있어서 과연 Flutter와 Dart 가 성장을 할 수 있을까 의문이었지만 이제 분위기가 급반전 하고 있는것 같다. 

 

각종 커뮤 사이트에서 Dart 언어를 칭찬하는 얘기들이 많이 나오는걸로 봐서  앞으로 지속적으로  성장을 할 것 같은데 시장이 포화가 되기전에 미리 선점해서 학습을 해놓으면 커리어에 도움이 될 것 같다.

 

아직은 스타트업에서 사용하거나 일반적으로 앱을 사용하는데 사용하는데  시장이 점점 커지게 되면 대기업 프로젝트에서도 도입되는 날이 오지 않을까?

 

 

728x90
728x90
반응형

보통 책판매 플랫폼에서 제공하는 프로그램이나 도서관 전자책 Viewer 프로그램, 교보문고, 밀리의서재, Ridi 북스 같은 전자책 Viewer 프로그램을 설치하면 반드시 설치되는 프로그램이 있다.

그 유명한 Fasoo DRM

https://namu.wiki/w/Fasoo%20DRM

 

Fasoo DRM - 나무위키

이 저작물은 CC BY-NC-SA 2.0 KR에 따라 이용할 수 있습니다. (단, 라이선스가 명시된 일부 문서 및 삽화 제외) 기여하신 문서의 저작권은 각 기여자에게 있으며, 각 기여자는 기여하신 부분의 저작권

namu.wiki

 

윈도에서 기본적으로 제공하는 캡쳐 프로그램이 있다.

Win + Ctrl + S

범위를 지정해서 화면 캡쳐를 하는 프로그램인데 거의 매일 아주 자주 흔히 쓰는 유용한 기능이다.

언젠가부터 이게 영역을 저장해도 메모리에 저장이 안되는 문제가 발생했다. 한 2주동안 문제가 뭔지 확인하고 찾아봤는데 역시나 Fasoo DRM 프로그램 밖에 문제될게 없어 보였다. 

WIn + Ctrl + S 기능이 안되어서 얼마나 번거롭고 불편한지 Windows를 다시 포멧해야 하나 고민도 했다.

그래서 과감하게 책뷰어 프로그램을 삭제하기로 결정했고 삭제를 단행했다.

다행히 예상대로 캡쳐 기능이 정상적으로 돌아왔고 아주 편하게 쓰고 있다.

 

그런데 도서관에서 무료로 대여해주는 전자책이나 전자잡지도 봐야 했기에 한참 고민을 하다가 방법을 생각해냈다.

바로 가상머신을 만들어서 윈도우를 하나 더 설치하는 거였다.

 

윈도우 캡쳐 안될 때 Fasoo 프로그램 설치 여부를 꼭 확인해 보자

 

VMWare 나 Hyper-V 같은걸로 윈도우를 하나 더 설치하자.

그리고 그 윈도우에는 아주 가끔 써야 하지만 시스템에 무리를 주는 프로그램들을 몽땅 설치해서 사용하자.

- 은행, 카드, 관공서 접속시 깔아야 하는 병맛스러운 보안 프로그램들

- 전자책, 전자잡지 Viewer 프로그램들 설치시 딸려오는 DRM 프로그램들

- 기타 아주 가끔씩 쓰이는 프로그램들

 

 

 

728x90

'Temp' 카테고리의 다른 글

내가 하는게 맞는건가? 어떤걸 해야하나.. 주절주절  (0) 2023.01.05
728x90
반응형

 

영단어 결합 신조어라서 어떻게 발음하는게 좋을지 몰라서 당황스러웠는데 유투브로 Pynecone 검색해서 버거형들이 발음하는걸 캐치했다.

Pynecone : 파인콘

우리나라에서는 파이콘이라고 부르는것 같은데 굳이 파인콘이라고 발음하는데 다른 발음을 붙일필요가 있나 싶다.

앞으로 파인콘이라고 발음하겠다.

 

Python + ne(?) + cone (솔방울)

파인콘 아이콘에서 확인 할 수 있듯이 솔방울이 파인콘의 공식 아이콘이다.

 

파인콘 깃허브에 가면 다음과 같이 설명되어 있다.

Pynecone은 오픈 소스 풀 스택 파이썬 프레임 워크로 몇 분 안에 웹 앱을 쉽게 구축하고 배포 할 수 있습니다.

기존 웹 개발의 유연성, 성능 및 사용자 지정 성과 결합 된 저 코드 프레임 워크의 사용 편의성과 접근성을 제공합니다. Pynecone은 오픈 소스이며 이전 웹 개발 경험이없는 사람들을 위해 쉽게 시작할 수 있도록 설계되었습니다.

Pynecone을 사용하면 데이터 과학자와 소프트웨어 엔지니어가 웹 개발을 배우지 않고도 빠르고 쉽게 고품질 웹 응용 프로그램을 만들 수 있습니다. 소규모 데이터 과학 프로젝트 / 내부 앱 또는 대규모 멀티 페이지 웹 앱을 구축하려는 경우 Pynecone에는 모든 프로젝트를 처리 할 수있는 도구와 기능이 있습니다. 이 프레임 워크는 성능, 확장 성 및 SEO에 최적화되어 있으므로 자랑스럽게 생각할 수있는 아름답고 매력적인 웹 앱을 만드는 데 집중할 수 있습니다

https://github.com/pynecone-io/pynecone

 

GitHub - pynecone-io/pynecone: Web apps in pure Python.

Web apps in pure Python. Contribute to pynecone-io/pynecone development by creating an account on GitHub.

github.com

 

 

https://pynecone.io/

 

Pynecone: The easiest way to build web apps.

Build anything, faster. Create your whole app in a single language. Don't worry about writing APIs to connect your frontend and backend. With Pynecone you can build anything from internal tools and data apps to complex multi-page apps. This entire website

pynecone.io

공식 사이트를 파인콘 프레임워크로 만들었다고 한다. 

워낙 간단해 보이는 홈페이지라서 뭐 크게 할말은 없지만 파이썬의 새로운 풀스택 프레임워크가 뜨고 있으니 한번 지켜봐야겠다.

 

우리 유명한 노마드코드 횽이 소개한 영상이다.

https://www.youtube.com/watch?v=47BL6WLZJ1g 

 

썸네일을 자극적으로 만들고 싶어서 문장을 좀 자극적이게 적었는데 내용을 들어보면 아직 성숙단계가 아니라서  물음표라고 하는것 같고 리엑트를 직접 학습하는게 더 빠를것 같다는 첨언도 했다. 하나의 언어로 여러가지 다른 언어 형태의 앱을 만드는건 앞으로도 꾸준히 발전할 부분인데 굳이 장점을 꼽아보자면 파이썬 학습만 꾸준히 해도 다른 프론트엔드 프레임워크를 학습하지 않아도 앱을 만들 수 있고 프론드엔드 & 백엔드 모두 파이썬 언어 하나로 개발을 할 수 있다는 통일성 이 마음에 든다.

 

얼마나 생산성이 있고 효과가 있을지 안써봐서 잘 모르겠지만 다른 언어들 golang, Rust. C#, java 같은 언어에서도 저런 형태의 프레임워크가 만들어지지 않을까 싶다.

 

암튼 시간내서 한번 테스트 해봐야겠다.

 

파인콘, 파인콘, 파인콘

728x90
728x90
반응형

프로그래밍을 하다가 특이한 수학기호가 나오면 어떻게 발음해야 할지 난감할 때가 자주 있다.

그래서 한번 찾아봤다.

Α/α(알파)
Β/β(베타)
Γ/γ(감마)
Δ/δ(델타)
Ε/ε(엡실론)
Ζ/ζ(제타)
Η/η(에타)
Θ/θ(쎄타)
Ι/ι(요타)
Κ/κ(카파)
Λ/λ(람다)
Μ/μ(뮤)
Ν/ν(뉴)
Ξ/ξ(크시)
Ο/ο(오미크론)
Π/π(피)
Ρ/ρ(로우)
Σ/σ(씨그마)
Τ/τ(타우)
Υ/υ(윕실론)
Φ/φ(휘)
Χ/χ(키 또는 카이)
Ψ/ψ(프시)
Ω/ω(오메가)
* 수학기호
σ : 소문자 시그마는 표준편차를 나타내는 기호
Σ : 대문자 시그마는 아래첨자와 위첨자를 기입하여 합에 관한 기호로 사용
i : 아이. 허수단위. 제곱해서 -1이 되는 수입니다.
cosθ: 코사인쎄타인 (하이퍼블릭코사인-쌍곡삼각함수중 하나로 수학에서는 거의 cosh를 사용합니다)
√ - 제곱근 또는 루트라고 읽습니다.
ㅠ - 파이 : 소문자 파이는 원주율을 나타내는 기호로 3.141592... 값을 가지며, 대문자 파이는 확률에서 중복순열을 나타내거나 위첨자 아래첨자와 함께 쓰는 경우 곱에 관한 기호가 됩니다.
∫ - 인테그랄 : 적분기호
∬ - 중적분 기호로, 적분을 두번 하라는 것입니다.
± - 플러스마이너스 : 플러스 또는 마이너스 라는 뜻
× - 곱하기÷ - 나누기
∏ - 대문자 파이
≠ - 같지앉다
∴ - 따라서 또는 그러므로
∵ - 왜냐하면
≒ - 약: 근사값을 쓸때 또는 양쪽 값이 거의 비슷할때 사용
≤ - (왼쪽이 오른쪽보다) 작거나 같다
≥ - (왼쪽이 오른쪽보다) 크거나 같다
- (왼쪽이 오른쪽보다) 작다
> - (왼쪽이 오른쪽보다) 크다
dθ - 디쎄타 - 미분에서 사용되는 기호.
≡ - 합동 또는 모듈로(mod)를 나타내는 도형의 합동 기호.
∈ - (왼쪽이 오른쪽의) 원소이다.
∋ - (오른쪽이 왼쪽의) 원소이다.
⊂ - (왼쪽이 오른쪽의) 부분집합이다.(오른쪽 집합이 왼쪽 집합을) 포함한다.
⊃ - (오른쪽이 왼쪽의) 부분집합이다.(오른쪽 집합이 왼쪽 집합을) 포함한다.
∪ - 합집합
∩ - 교집합
∀ - 임의의
∃ - 존재한다. exist.
** 기타 기호.
Å - 옴스트롱 또는 옴고스트롱.
μ(마이크로) - 10의 -6승. 즉, 1/1000000의 크기.
℉ - 화씨. 온도 단위
℃ - 섭씨. 온도의 단위.
㎛(마이크로미터) ㎝(센티미터) - 길이의 단위
㎟(제곱밀리미터) ㎢(제곱키로미터) - 넓이의 단위
㎣(세제곱밀리미터) ㎤(세제곱 센티미터) ㎥(세제곱 미터)
㎦(세제곱 키로미터) - 부피의 단위.
㏈ - 데시벨. 소리의 단위
㎲ -마이크로초. 시간의 단위
집합기호 : { }, ⊂,⊃,⊆,⊇,
명제기호 : ∧,∨,←,→,⇔,⇒,⇒
도형기호 : ∠(각),∽(닮음),≡(합동),ꁚ(평행),⊥(수직)
대소관계 : <, >, ≤,≥,
각종괄호 : (,),{,},[,]
적분기호 : ∫, ∬, ∮
미분기호 : ∂(편미분)
삼각함수 : sin, cos, tan, sec, cosec, cot, sinh, cosh, tanh, sech, cosech, coth, 각각의 함수에 역함수 기호(^-1)를 붙이면
arc삼각함수(=역삼각함수)가 된다.
기타 : ∞(무한대), !(팩토리얼,factorial), 기호가 표시는 안됩니다만.세제곱근호, 네제곱근호, 선적분, 면적분, 벡터기호

 

혹시 더 궁금한게 있다면 댓글에 등록해주면 찾아보겠다.

728x90
728x90
반응형

솔라나(SOL)

 

최근 FTX가 파산하면서 FTX의 지지를 받고 있는 Solana 코인과 그 생태계에 있는 코인들이 대부분 폭락을 했었습니다.

저도 Solana 홀더로서 가슴이 아프더군요. ㅠ.ㅠ

1년만에 시총 5위에서 17위로 밀려나는 안좋은 상황이 발생했군요.

2023년 1월 2일 기준으로 시총 4조6777억원을 찍었는데 정확히 1년전인 2022년 1월 2일에는 64조8563억원 이었던것을 감안하면 거의 망했다고 볼 수 있습니다.

지속적으로 발생한 네트워크 중단사태, 해킹사태 그리고 최대 원흉인 뽀글이의 FTX와 그 연인인 알리메다CEO 파산 사태가 겹치면서 솔라나 생태계의 우수한 토큰업체 몇군데가 이더리움으로 옮긴다는 기사까지 나왔습니다.

솔라나 NFT의 대장 프로젝트라고 불리던 DeGods(디갓)이 이더리움 시장으로 옮길꺼라는 발표가 있었죠.

그렇지만 전 팔지 않고 버텼습니다.

왜냐하면 솔라나가 가지고 있는 기술적인 우수함과 절대 망하지 않을꺼라는 확신을 가지고 있었기 떄문이죠.

최근 몇 일 동안 최저점 대비 200% 정도 오른 상황인데요. 물을 탈까말까 고민하다가 그냥 지켜보기로 했습니다. 아무래도 3만8천원까지는 올라기지 않을까 조심스레 예측하고 있기는 한데 워낙 급변하는 코인 시장이다보니 결정내리기가 쉽지 않은것 같습니다.

솔라나가 이러한 사태를 타개하기 위해 2022년 12월 22일 자체 스마트폰 개발을 선언했는데요. 전 조금 의문입니다. 

너무 포화된 시장에 하드웨어, 소프트웨어 기술이 없는 솔라나가 자체적인 스마트폰을 개발해서 어느정도 성과를 이뤄낼 수 있을지 전혀 예측이 안됩니다. 소프트웨어야 돈으로 우수한 인재를 산다 치더라도 하드웨어 시장을 어떻게 뚫을건지 걱정이 되네요.

 

 

만약 이렇게 진행이된다면 솔라나의 행보를 보고 홀더에서 빠져나오는 전략을 취해야 하지 않을까 싶습니다.

이번 비트의 급상승은 언제까지 지속될지 모르겠지만 예전의 불장을 기대하기는 어렵지 않을까요?

심리가 죽었고 세계 경제도 흐름이 안좋았던 상황이라 올리는데 한계가 분명히 존재합니다.

 

 

저는 이제 지금 투자된 금액 말고는 더 이상 가상화폐쪽에 투자하지 않을 생각입니다. 

똥손인것 같아요. @_@;;;

제가 잘 할 수 있는것에 집중해야겠습니다.

728x90
728x90
반응형

Java 개발자를 위한 Rust, 파트 2

우리는 지금까지 어디로 갔습니까?

Java 개발자를 위한 Rust 시리즈의  번째 기사 에서 우리는 몇 가지 기본 구문, 일부 패턴 일치를 보았고 간략하게 다루었으며 가장 중요한 것은 프로그램의 데이터가 있는 위치에 대해 추론하려고 했습니다.enum

우리가 신속하게 코드 라인을 저장하려고 시도했을 때 RAII로 인해 중요한 리소스의 범위를 실수로 변경했고 코드를 컴파일하려고 할 때 빌림 검사기 에서 오류가 발생했습니다.

$ rustc greeter.rs
error[E0716]: temporary value dropped while borrowed
 --> greeter.rs:6:43
  |
6 |     let anybody_at_all = env::args().collect::<Vec<String>>().get(1);
  |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^       - temporary value is freed at the end of this statement
  |                          |
  |                          creates a temporary which is freed while still in use
7 |
8 |     let who: &str = if let Some(one) = anybody_at_all {
  |                                        -------------- borrow later used here
  |

두려운 차용 검사기 는 소유borrow later used here 한 값에 대한 참조(차용)를 효과적으로 알려줍니다. 이 경우 소유자가 해제된 동안 임시 가 사용됩니다. 이것은 관리되는 언어에서 오는 Rust를 시도하는 개발자들에게 너무 잘 알려진 오류 메시지입니다. 당신이 직접 Rust를 가지고 놀기 시작했다면 조만간 모험을 하면서 그런 메시지를 접했을 가능성이 있습니다.

Java에는 사용되지 않을 때만 메모리를 해제하는 가비지 수집기가 있을 뿐만 아니라 완전히 투명하게 힙 할당을 최적화할 수 있는 컴파일러도 있습니다. 이렇게 하면 메모리, 해제 또는 메모리 할당 위치(힙 또는 스택)에 대해 생각하지 않아도 됩니다. 반면에 Rust는 개발자에게 메모리 할당 위치와 방법에 대한 결정을 내립니다. 그것은 큰 힘을 동반하지만, 또한… 예, 책임이 있습니다. 적어도 컴파일러는 안전하지 않은 코드를 생성하도록 허용하지 않습니다. 때로는 컴파일러가 작업을 완료하도록 허용하지 않는 것처럼 느껴지기도 합니다. 이것은 일반적으로 프로그램을 통해 데이터가 "흐르는" 방식을 설명하지 않는 코딩 패턴에서 비롯됩니다. 왜냐하면 JVM은 이러한 것들에 대해 생각할 필요가 없고 누구라도 가리킬 수 있는 거대한 객체 바다를 생성하지 않도록 우리를 망쳤기 때문입니다. 모든 것.

소유권 및 이동

cargo new. _ 첫 번째 인수가 있는 경우 전달되도록 코드를 약간 변경할 것입니다. 그리 놀라운 방법은 아닙니다.

use std::env;

fn main() {
    let who = env::args().nth(1).unwrap_or(String::from("World"));
    println!("Hello, {who}!");
}

잠깐만! 이것은 우리가 이전에 본 것과는 다릅니다. 지금까지 우리가 했던 모든 작업이 한 줄짜리인 이유는 무엇입니까? 음… 예. 읽기 쉽게 만들 수 있었습니다 . 또는 적어도 이것이 읽기 쉽기를 바랍니다. 이제 반복자에서 두 번째 .nth(1)항목 을 가져오는 데 필요한 모든 것은 Args여전히 Option<String>​​; 그런 다음 프로그램에 제공된 인수  있는 경우 .unwrap밖으로 이동 합니다 . 반면에 가 있는 경우 대신 메서드에 제공된 인수에서 힙 할당 인스턴스를 만듭니다 .String OptionSome_orNoneString"World": &str

위의 코드에는 다음과 같은 새로운 구문이 있습니다 . 유형 에서 호출 String::from()되는 함수 입니다. 이는 정적 메서드 호출과 동일합니다. 여기 에서 참조하는 는 에서 찾을 수 있습니다 . A 는 Java에서 와 같이 명명된 필드에 관련 데이터를 보유합니다 . 그러나 우리는 그것에 대해 조금 후에 돌아올 것입니다.from()Stringfrom()struct Stringstructclass

그래서 밖으로 옮기는 이 사업  무엇입니까? 이전 게시물에서 보았듯이 는 어딘가에 살아야 합니다 . 그것이 Rust가 소유권이라고 부르는 것입니다. 그리고 모든 데이터의 소유자 는 한 명만 있을 수 있습니다 . 프로그램에 전달된 인수가 있는 경우 에 대한 호출 은 해당 의 소유자인 변형 에서 해당 인수를 반환합니다 . 즉, 범위를 벗어나는 즉시 콘텐츠도 -ped되고 the 가 해제됩니다. 그러나 우리는 우리의 작은 프로그램 전체에서 간접 참조 를 다루고 싶지 않습니다 . 전달 된 인수인지 또는String Option::SomeString env::args().nth(1)StringOption::SomeStringDropStringOptionString"World", 우리는 우리가 인쇄 who할 적절한 것을 가리키는 것 외에는 별로 신경 쓰지 않습니다. String이것이 .unwrap_or()우리를 위해 하는 일입니다.

두 개의 개별 비트를 분해해 보겠습니다. 먼저 Option<String>단순화를 위해 를 다룰 것이므로 먼저 코드를 리팩터링하여 다음을 얻습니다.

let anybody_at_all: Option<String> = env::args().nth(1);
let who: String = anybody_at_all.unwrap_or(String::from("World"));

이제 가 있으므로 프로그램에 항상 인수가 제공 anybody_at_all: Option<String>된다고 가정해 봅시다 . 다음과 같이 메서드 호출을 직선으로 바꿀 수 있습니다 ..unwrap_or.unwrap()

let who: String = anybody_at_all.unwrap();

이 코드는 이제 panic실제로 제공되는 인수가 없을 것입니다. 먼저 인수를 제공한 다음 생략합니다.

$ cargo run -- Jane
   Compiling rusty-java-2 v0.1.0
    Finished dev [unoptimized + debuginfo] target(s) in 0.75s
     Running `target/debug/rusty-java-2 Jane`
Hello, Jane!

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/rusty-java-2`
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/main.rs:5:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

좋지 않습니다. 하지만 지금은 무시하고 .unwrap_or곧 우리 버전으로 돌아갈 것입니다. 실제로 성공하는 경로에 집중하여 호출 하면 it이 가진 anybody_at_all.unwrap()소유권을 변수로 이전합니다. 제공된 인수, 즉 이 예에서 from 은 우리의 that 에서 로 이동 했습니다 . 어느 시점에서 당신은 아마 무슨 일이 일어났는지 궁금할 것이고 당신이 묻는 것이 맞을 것입니다. 시행 착오가 여기서 다시 우리의 접근 방식으로 남아 있습니다 . 값 을 다시 시도해 봅시다 .Stringwho: StringString"Jane"Option::Someanybody_at_allwhoanybody_at_all.unwrap()

let anybody_at_all: Option<String> = env::args().nth(1);
let who: String = anybody_at_all.unwrap();
let _again: String = anybody_at_all.unwrap();

무엇이 _again될까요? (밑줄로 변수 이름을 시작하면 컴파일러에 사용할 계획이 없음을 알립니다). 참고가 아닙니다. 또한 에 String포함 Option되어 있으므로 입니다. 그렇다면 원래 문자열의 복사본일까요? 이것을 실행해 봅시다:

$ cargo run -- Jane
   Compiling rusty-java-2 v0.1.0
error[E0382]: use of moved value: `anybody_at_all`
   --> src/main.rs:6:26
    |
4   |     let anybody_at_all: Option<String> = env::args().nth(1);
    |         -------------- move occurs because `anybody_at_all` has type `Option<String>`, which does not implement the `Copy` trait
5   |     let who: String = anybody_at_all.unwrap();
    |                       -------------- -------- `anybody_at_all` moved due to this method call
    |                       |
    |                       help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
6   |     let _again: String = anybody_at_all.unwrap();
    |                          ^^^^^^^^^^^^^^ value used here after move
    |
note: this function takes ownership of the receiver `self`, which moves `anybody_at_all`
   --> .../lib/rustlib/src/rust/library/core/src/option.rs:775:25
    |
775 |     pub const fn unwrap(self) -> T {
    |                         ^^^^

For more information about this error, try `rustc --explain E0382`.
error: could not compile `rusty-java-2` due to previous error

좋아요, 무서운 오류 메시지입니다: move occurs because …​ does not implement the Copy trait?! 글쎄, 원본의 사본은 String분명히 없습니다. 그 가설에 대해 너무 많이. 그러나 우리는 무언가 움직 인 것을 봅니다 ! anybody_at_all moved 오류 메시지가 나타납니다!  Option자체가 그랬다. 어떤 fn unwrap(self)메서드 때문에 우리는 실제로 호출했습니다. 나중에 구문으로 돌아갑니다. 그러나 무슨 일이 일어났는가는 호출 anybody_at_all이 소비되는 결과를 낳았고 , 그 동안 포함된 it의 소유권 String을 who. 그래서 우리가 그것으로 할 수 있는 것은 아무것도 없고 anybody_at_all, 그것은 "사라지고" 우리가 invoke 를 했던 5행.unwrap() 너머에서 사용될 수 없습니다 .

소유권은 매우 유사한 방식으로 동일한 범위 내에서 한 변수에서 다른 변수로 이전됩니다.

let who: String = anybody_at_all.unwrap();
let moved: String = who;
println!("Hello, {who}!");
println!("Hello, {moved}!");

이것은 우리 가 변수에서 변수로 소유권을 이전하기 때문에 컴파일 되지 않습니다 . 따라서 이후에는 사용할  없으며 더 이상 사용할 수 없습니다.Stringwhomovedwhoprintln!

전화는 어때 .unwrap_or(String::from("World"))? 우리가 변종 panic을 다루는 경우를 제외하고는 정확히 동일하게 작동합니다 . Option::None이 경우 제공된 인수를 대신 반환합니다. 이것은 제네릭 형식 Option<T>이며 unwrap_ora T를 default: T 인수로 사용합니다.  String, 이 경우 a를 전달해야 합니다. 그렇기 때문에 이전 게시물에서 수행한 작업과 &str대신 처리한 문자열과 달리 힙에서 문자열을 인스턴스화해야 합니다. 이 프로그램은 "World" 항상 힙에 문자열을 할당합니다 . 이것은 메서드에 전달되는 인수이며 따라서 평가되어야 합니다. 즉, 함수 String::from가 항상 호출됩니다. 달리는 대안이 있습니다cargo clippy실제로 사용할 것을 권장합니다. 이는 Java의 람다 식에 해당하는 Rust를 사용하여 사용할 기본값을 느리게 평가하고 인수가 이미 제공된 경우 String불필요하게 힙에 할당하는 것을 방지 합니다. "World"그래도 나중 게시물을 위해 보관하겠습니다. 그래도 자유롭게 시도해 보세요!

struct그리고 차용

이제 우리는 소유권과 이사에 대해 상당히 잘 이해했으므로 차입에 대해 좀 더 자세히 살펴볼 때입니다. 앞서 말했듯이 참조는 값을 빌린 것입니다. str로드된 이진 코드에서 a에 대한 참조 또는 String실행 파일에 전달된 인수에서 가져온에 대한 참조를 다루었기 때문에 이전 게시물에서 상당한 양을 차용했습니다 . 이러한 차용은 모두 "읽기 전용"이었습니다. 참조가 가리키는 것을 변경할 수 없다는 의미입니다. &mut그들은 변경 가능한 참조인 참조 에 반대합니다 .

rustc여기 에 우리에게 부과할 중요한 규칙이 있습니다.

주어진 시간에 하나의 가변 참조 또는 여러 불변 참조를 가질 수 있습니다.
— The Rust Book
참조 규칙

즉, "살아 있는" 불변 참조자는 0개 이상 있을 수 있지만, 가변 참조자가 하나(그리고 하나만!) 있는 경우에는 불변 참조자가 0개만 있을 수 있습니다. 이는 값이 변경되는 동안 아무도 값을 읽지 않도록 보장합니다. 이것은 동시성 코드에 유용하지만, 단일 스레드 코드도 이러한 보장으로부터 이점을 얻는다는 것을 조금은 알게 될 것입니다.

그러나 이것이 프로덕션에서 무작위로 발생하는 버그가 아니라 컴파일 타임에 코드에서 전체 범주의 버그를 제거하는 데 어떻게 도움이 되는지 살펴보기 전에 RuntimeException먼저 참조 및 차용이 struct해당 impl블록과 어떻게 작용하는지 살펴보겠습니다. 먼저, structRust에서 a를 선언하는 방법은 다음과 같습니다.

struct Greeter {
    person: String,
}

structRust 의 A class는 Java의 a와 동일합니다. 먼저 struct키워드를 사용하여 선언한 다음 원하는 이름을 지정합니다. 그것이 선언하는 필드는 우리가 지금까지 본 Rust 구문을 따릅니다: <name>: <type>. 위의 예에서 person필드를 선언하는 줄은 쉼표( ,)로 끝납니다. Greeter이것은 구조체 의 마지막(유일한) 필드이므로 꼭 필요한 것은 아닙니다 . 그러나 쉼표가 필요하기 전에 선언되는 필드입니다. 항상 필드 선언을 쉼표로 끝내는 것이 좋은 방법으로 간주되므로 새 항목을 추가해야 하는 경우 버전 제어 시스템의 diff가 더 깔끔해집니다.

현재 우리 는 Java보다 structC에 더 가깝 습니다. 이 단계에서 아마도 생성자와 몇 가지 메서드를 예상할 것입니다. 전자부터 시작하겠습니다. 이 특별한 경우에는 생성자 자체가 필요하지 않습니다. 이 모든 것을 동일한 파일에 넣기 때문에 가시성은 중요하지 않습니다.  명시적으로 . 필드도 마찬가지입니다 . 즉 , 함수 의 어느 지점에서나 다음과 같은 구문을 사용하여 인스턴스화할 수 있습니다.structclassstructpubpersonmainGreeter

let greeter = Greeter {
    person: String::from("Jane"),
};

그리고 Rust의 Java에서 알 수 있듯이 생성자 가 없습니다. struct Greeter예를 들어 일부 인수 조작을 수행 하는 함수를 정의할 수 있습니다. a에 함수를 추가하는 것은 동일한 이름 struct의 블록으로 수행됩니다 . impl다음은 a 를 생성 하고 반환 하는 Greeter::new함수 의 예입니다( 참조가 아닌 자체).Personstruct

impl Greeter {
    fn new(person: String) -> Self {
        Self {
            person,
        }
    }
}

pub fn new다시 말하지만, 이 범위 외부에 노출되어야 하는 경우 함수는 로 public으로 선언 됩니다. 함수가 a 의 소유권 을 갖는 것을 볼 수 있습니다 String. 즉, 호출자가 String소유권을 이 함수로 옮긴다는 의미입니다. →그리고 화살표 a... 로 표시된 함수가 반환됩니다 Self.

Selfimpl블록 유형에 대한 자리 표시자입니다 . 이는 리팩터링할 때나 유형이 다소 장황할 때 유용합니다. 그러나 메서드 서명을 fn new(person: String) → Greeter. 함수 본문인 중괄호 안의 블록을 따릅니다. Greeter그러나 이번에 생성할 때 필드 person가 동일한 이름의 변수를 소유하도록 명시적으로 알리지 않습니다. 이전에 새로 만든 : 과 연결했을 때와 달리 String: person: String::from("Jane"). 이름이 같기 때문에 앞에 를person: 붙일 필요가 없습니다 . 중복되는 것으로 간주되므로 필요하지 않습니다. 마지막으로 본문의 한 줄은 ;새로 생성된Greeter인스턴스를 호출자에게, 즉 소유권을 호출자에게 이동합니다. 이 새로 생성 struct된 것이 스택에 생성되었다는 점도 언급할 가치가 있습니다. person의 이름 바이트가 결국 힙에 있더라도 이것은 String.

다시 Java Greeter::new의 메소드와 동일합니다 . static그렇다면 인스턴스 메서드를 어떻게 추가하시겠습니까? 먼저 인스턴스 메서드가 무엇인지 생각해 보겠습니다. 인스턴스 메소드는 객체 자체의 인스턴스에 작용하는 메소드입니다. 런타임에 발생하는 일은 인스턴스에 대한 참조가 일반 이전 함수에 암시적으로 전달된다는 것입니다. Rust는 이것을 좀 더 명시적으로 만듭니다. 다음은 구조체 에 .hi()메서드를 추가하는 코드입니다 .Greeter

impl Greeter {
    fn new(person: String) -> Self {
        Self {
            person,
        }
    }

    fn hi(&self) {
        let who = self.person.as_str();
        println!("Hello, {who}!");
    }
}

...에 대한 참조 self? 이번에는 소문자 자기? 예. 이것이 Rust가 인스턴스 메서드를 정의하는 방법입니다. 첫 번째 인수는 &self실제로 의 약어 이므로 의 유형에 대한 참조인 바인딩 이름이 지정 self: &Self됩니다 . 첫 번째 인수는 a , a 또는 a 일 수 있습니다 . 우리는 처음에 변형을 보았습니다. 그것은 인스턴스를 소비하는 인스턴스 메서드입니다. 따라서 메서드를 호출하는 데 사용된 바인딩은 일단 호출되면 쓸모 없게 됩니다. 이 구조체와 관련된 상태를 변경하기 때문에 변경 가능한 참조가 필요하다고 컴파일러에 알립니다. 한 가지 예는 Java의 setter이거나 예를 들어 . 제공된 새 항목을 재할당하려면 selfSelfGreeter&self&mut selfselfselfOption.unwrap()&mut selfset_personstruct GreeterString우리 person필드에 대한 참조는 변경 가능해야 합니다.

fn set_person(&mut self, person: String) {
    self.person = person;
}

로 선언 하면 필드 에 새 값을 할당할 때 &self변경하려고 시도하므로 컴파일러에서 불평할 것 입니다.selfperson

$ cargo run -- Jane
   Compiling rusty-java-2 v0.1.0
error[E0594]: cannot assign to `self.person`, which is behind a `&` reference
  --> src/main.rs:32:9
   |
31 |     fn set_person(&self, person: String) {
   |                   ----- help: consider changing this to be a mutable reference: `&mut self`
32 |         self.person = person;
   |         ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written

For more information about this error, try `rustc --explain E0594`.
error: could not compile `rusty-java-2` due to previous error

아래는 main.rs이러한 모든 변경 사항이 포함된 현재 상태의 전체 내용입니다. 그리고 몇 가지 작은 변경 사항이 더 있습니다.

   

이제 우리는 메서드 person뿐만 아니라 참조를 반환하는 필드에 대한 getter도 가지고 있습니다 . bye()그 메서드의 본문은 이전에 본 것과 약간 다릅니다 hi(). 둘 다 사실상 동일합니다. 사람의 이름을 인쇄하기 위해 사람의 참조를 얻습니다. 23번째 줄  메서드 hi()에서 self.person필드 를 가져오고 사용할 .as_str()a를 반환하는 the를 호출하는 &str 반면, 28번째 줄println! 에서는 매크로 호출 내에서 the 에 대한 참조 , 즉 a 를 가져 &옵니다 . 두 경우 모두 구조체 밖으로 이동하지 않습니다 . 그 이동은 불법입니다. 우리는 필드만 참조합니다.self.person&Stringself.person

이제 실행하면 다음과 같은 결과가 나타납니다.

❯ cargo run -- Jane
   Compiling rusty-java-2 v0.1.0
    Finished dev [unoptimized + debuginfo] target(s) in 0.59s
     Running `target/debug/rusty-java-2 Jane`
Hello, Jane!
... and goodbye, Jane!

이제 이 구조체를 사용하여 차용을 약간 재생하면 이전 의 참조 규칙을 테스트할 수 있습니다.

주어진 시간에 하나의 가변 참조 또는 여러 불변 참조를 가질 수 있습니다.
— The Rust Book
참조 규칙

예를 들어 이것이 무엇을 할 것이라고 생각합니까?

let mut greeter = Greeter::new(String::from("Jane"));

let reference = &greeter;
greeter.set_person(String::from("John"));
reference.hi();

글쎄, 그것은 우리의 간단한 규칙을 위반하기 때문에 컴파일되지 않을 것입니다:

let reference = &greeter;
                -------- immutable borrow occurs here
greeter.set_person(String::from("John"));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
reference.hi();
-------------- immutable borrow later used here

의 메서드 선언을 보면 문제가 표시됩니다 set_person(&mut self, person: Person). 가 필요 &mut self하므로 메서드를 호출할 때 묵시적으로 greeter가변적으로 차용하려고 시도합니다. 불변 참조가 아직 살아 있기 때문에 우리는 할 수 없습니다. greeteron 을 호출하기 위해 대신 사용한다면 .hi()불변 참조는 "죽은" 상태가 되고 코드는 작동할 것입니다…

이 다른 간단한 예가 무엇을 할 것이라고 생각하십니까?

let mut greeter = Greeter::new(String::from("Jane"));

let person = greeter.person();
greeter.set_person(String::from("John"));
greeter.hi();
println!("Our previous person: {person}");

person이것은 우리가 인사 하는 사람 의 필드에 대한 참조를 차용하고 있기 때문에 조금 덜 명확할 수 있습니다 . 그러나 생각해 보면 결과가 이전과 거의 같다는 사실에 놀라지 않을 것입니다.

let person = greeter.person();
             ---------------- immutable borrow occurs here
greeter.set_person(String::from("John"));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
greeter.hi();
println!("Our previous person: {person}");
                                ------ immutable borrow later used here

빌림 자체의 "전이성"은 .person컴파일러 greeter에 의해 추적되므로 동일한 오류가 다시 발생합니다. 내부 에 대한 참조가 아직 있는 동안에는 내부 를 새 것으로 set_person교체 할 수 없습니다 . 이를 교체하면 여전히 사용 중인 이전 값을 -ping하는 것을 의미합니다. 마지막 참조가 만료된 후에만 정리할 가비지 수집기가 없다는 것을 기억하십시오.StringgreeterDrop

이 간단한 예제를 사용하여 참조의 수명 주기 를 실험 하고 참조 규칙이 어떻게 적용되는지 확인할 수 있습니다. Java 개발자로서 이 규칙에 익숙해지고 코드에서 데이터를 처리하는 방법에 대해 더 많이 생각하는 데 시간이 걸립니다. Rust는 데이터와 참조를 저장하는 위치와 방법에 대해 조금 더 생각해야 합니다.

지금 이 규칙이 왜 있는지 궁금하거나 때때로 실제로 도움이 되기보다는 제약이 더 많다고 느꼈을 수도 있습니다. 다른 스레드에 의해 동시에 수정되는 것에 대한 참조 외에 greeter.person, 이 가드에 값을 해제하는 것보다 더 많은 가치가 추가되지 않습니다… 또는 거기에 있습니까? 다음과 같은 간단한 자바 코드를 살펴보겠습니다.

List<Integer> list = new ArrayList<Integer>();

list.add(1);
list.add(2);
list.add(3);

for (Integer i : list) {
    System.out.println(i);
    list.remove(0);
}

목록을 반복하면서 값을 인쇄하고 이동하면서 제거합니다. 이 멍청한 예제와 달리 "실제" 코드에서는 이것이 계속 발생 합니다. 한동안 Java를 사용해 왔다면 이 작업이 이미 명확할 수 있지만 실행 결과는 다음과 같습니다.

1

Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
	at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
	at Program.main(Program.java:12)

글쎄, 우리는 이것에 대해 너무 멀리 가지 않았습니다! A ConcurrentModificationException, 단일 스레드에서! 이제 동일한 코드를 Rust에서 사용해 봅시다:

let mut items = vec![1, 2, 3];

for i in &items {
    println!("{i}");
    items.remove(0);
}

여기서 무슨 일이 일어나고 있는지 먼저 설명하겠습니다. Vec<i32>편리한 vec!함수형 매크로에서 다시 생성 합니다. 벡터에 있는 요소의 유형은 i32, 부호 있는 32비트 정수 - Java의 int입니다. 이는 Rust에서 정수 리터럴이 평가하는 것이기 때문입니다.

그런 다음 vec 에 대한 참조 를 반복합니다 ?! 음 ... 아니. 거기에 있는 for 루프에는 컴파일러에 의해 추가된 구문 설탕이 있습니다. for i in items- 앰퍼샌드 없이 - 는 와 동일합니다 for i in items.into_iter(). from 의 소유권을 iterator into_iter() 로 이동 하는 곳 입니다. 결국 각 항목의 소유권은 루프로 이동됩니다. While  루프 의 각 요소에 대한 참조를 제공 하고 컬렉션을 그대로 유지하는 와 동일합니다.Vecveci in &itemsi in items.iter()vecitems

루프 블록은 이제 간단해야 합니다. 이것을 실행하면 어떻게 될까요?

for i in &items {
         ------
         |
         immutable borrow occurs here
         immutable borrow later used here
    println!("{i}");
    items.remove(0);
    ^^^^^^^^^^^^^^^ mutable borrow occurs here

음, 참조 규칙은 우리가 우리의 에 대한 변경 가능한 참조를 가져오는 것을 불가능하게 만들 것입니다. items우리는 암묵적으로 which 가 그것을 변경하기 위해 .removea &mut self를 호출하여 수행 Vec합니다. 우리가 불변 참조를 사용하여 해당 Vec.

이 코드는 어떻습니까?

let mut items = vec![1, 2, 3];

for i in &items {
    for i in &items {
        println!("{i}");
    }
}

이는 참조 규칙을 위반 하지 않습니다 . 키워드가 mut 있지만 참조가 아니라 를 소유하는 변수에 있습니다 Vec<i32>. 그런 다음 중첩 반복으로 이동하여 최대 2개의 불변 참조가 동시에 활성화되며 이는 규칙에 위배 되지 않습니다 . 이 코드는 이러한 루프 후에 itemsthen:을 변경하지 않고 variable does not need to be mutable첫 번째 i가 사용되지 않는 경우 컴파일러에서 경고를 생성하도록 if this is intentional, prefix it with an underscore합니다.

그렇다면 상황은 Drop어떻습니까?

인스턴스가 범위를 벗어나면 컴파일러는 Drop인스턴스를 -ping하는 역할을 하는 일부 코드를 삽입합니다. 즉, 더 많은 인스턴스, 파일 디스크립터, 소켓 등 보유할 수 있는 모든 리소스를 해제하고 결국에는 String 인스턴스용 힙의 메모리와 같이 사용한 메모리를 해제합니다.

Rust가 리소스 해제를 처리하는 방법을 이해하기 위해 약간의 실험을 시작하겠습니다. 로 빌드한 이 hi/bye "관용구"를 기반으로 빌드 Greeter하지만 약간 변경합니다. "안녕하세요!" 한 번은 항상 "bye"라고 표시되어 있는지 확인하십시오. 바로 시작하겠습니다.

   

좋아, 그래서 우리는 이미 무엇을 알고 있습니까? struct두 가지 유형 을 선언 합니다. Scope  TrackedScope. 둘 다 String이라는 힙 할당 필드 를 포함하는 동일한 구조를 갖습니다 name.

필드에는 하나 의 Scope기능과 하나의 메서드가 있습니다. 이 함수는 간단하지만 이전 에 약간의 유용성을 추가하고 Greetera 를 생성하기 전에 &str할당된 힙으로 변환합니다 . 방법 은 조금 더 흥미롭습니다. 참조를 받지 않고 대신 소비 합니다! 그러나 그렇게 하기 전에 범위가 이제 시작되었음을 인쇄한 다음 인스턴스에서 새로 생성된 인스턴스로 이동 한 다음 반환된 인스턴스 를 반환합니다. 따라서 이름은 보존되지만 원래 인스턴스는 삭제됩니다.Stringstruct Scopestart&selfselfTrackedScope StringScopeTrackedScopeScope

에 대해 얘기 Drop! 에 대한 impl블록 도 TrackedScope있지만 특성을 구현합니다 Drop. fn drop(&mut self)Java 인터페이스와 동등한 특성 은 범위가 종료되었음을 인쇄하여 여기에서 구현 하는 단일 메서드를 선언합니다 . 해당 drop메서드 호출은 컴파일러가 올바른 위치에 자동으로 추가하는 것입니다. 코드에서 수동으로 해당 메소드를 호출할 수는 없지만 컴파일러는 (다시!) 이를 금지합니다.

수동으로 drop무언가를 원 .drop()하고 인스턴스에서 호출하는 경우 표준 라이브러리에서 사용할 수 있는 편리한 유틸리티 함수가 있습니다 std::mem::drop. drop그 기능이 얼마나 특별한지 , 신뢰할 수 없는 실제 인스턴스에 어떤 종류의 마법을 사용하는지 궁금하실 것 입니다! 자, 한번 살펴봅시다! 그 아래에는 이 신비한 유틸리티 함수의 전체 소스 코드가 있습니다.

pub fn drop<T>(_x: T) {}

기다리다?! 뭐라고요? 그것은… 비어 있습니다!

예 그렇습니다. 함수 서명에서 마술이 다시 발생합니다. 전달된 인수의 소유권을 갖습니다! 이 메서드는 범위가 없는 일반적인 over T이므로 무엇이든 허용합니다. 그리고 그것 으로 절대 아무것도 하지 마십시오 ! 하지만 그 함수를 호출할 때 의 소유권 _x이 이 범위로 이동한 다음… 컴파일러는 범위를 벗어나는 것을 확인하고 필요한 정리 코드를 삽입합니다!

이제 아래의 몇 가지 경우를 고려하여 코드에서 -ing이 Scope어떻게 발생하는지 지금 사용하겠습니다 .drop

   

주목할 가치가 있는 것은 우리가 10행 에서 끝나는 7행 에 합성 블록을 추가한다는 것 입니다. 또한 범위 는 시작할 때 변수에 바인딩되지 않습니다. 그렇다면 출력은 어떻게 되어야 한다고 생각하십니까? 이것을 실행하고 보자:two

Scope 1 started
Scope 2 started
Scope 2 ended!
Scope 3 started
Scope 3 ended!
Scope 4 started
Scope 4 ended!
Scope 1 ended!

아마 놀랍지 않게, 시작 되기 직전 에 라인 10three 의 블록 끝에서 드롭됩니다 . 반환된 항목을 바인딩하지 않으므로 시작 직후 삭제되지만 바로 정리할 수 있습니다. while 은 해당 블록의 마지막 문과 유사하게만 작동합니다. 외부 범위에서 먼저 then 을 시작하여 결과를 로컬 변수에 바인딩하고 역순으로 -ped되는 것을 볼 수 있습니다 . first , then . 말이 되네요. 나중에 선언된 구조체 바인딩은 이전에 선언된 항목에 대한 참조를 보유할 수 있으므로 역순으로 삭제하면 제대로 정리됩니다!fourtwoTrackedScopethreeonefourdropfourone

요약하자면

그것은 다시 꽤 많은 내용이었습니다. 우리는 지금까지 소유권 의 개념을 훨씬 더 깊이 탐구했습니다. 주어진 데이터 조각의 소유자는 단 한 명뿐입니다. 그러나 해당 소유권은 이전될 수 있으며 이동 이라고도 합니다 . 그런 다음 참조 규칙에 따라 데이터에 대한 참조를 빌릴 수 있는 방법을 살펴보았습니다 . 마지막으로 Rust 컴파일러가 Drop 구조체 인스턴스를 -ping하여 리소스를 해제하는 방법을 확인했습니다.

우리는 실제로 struct우리 자신의 새로운 유형을 선언하고 함수와 메소드를 추가함으로써 이 작업의 대부분을 수행했습니다. &self이렇게 함으로써 우리는 구조체 에 선언될 수 있는 &mut self  가지 다른 유형의 메서드를 살펴보았습니다 self.

마지막으로 Rust에서 for 루프가 작동하는 방식과 Java와 다른 점을 엿볼 수 있습니다. 또한 Rust 표준 라이브러리의 코드를 사용하여 위 원칙의 일부 사용법을 설명했습니다. Java와 마찬가지로 해당 소스 코드를 읽을 수 있으며 Rust 표준 라이브러리 개발자가 언어를 활용하여 몇 가지 기본 문제를 해결하기 위해 코드를 작성하는 방법에 대해 더 잘 알기 위해 일부 시간을 할애하여 일부를 읽는 것이 좋습니다. 우리가 std::mem::drop().

cargo clippy 코드를 자주 실행 하라! 일단 컴파일되면 얻은 것을 리팩토링하는 데 시간을 보내십시오. 그리고 재실행 clippy! 자신의 용어로 언어를 탐색하는 데 시간을 보내는 것이 아마도 Rust 작성을 더 잘 다룰 수 있는 가장 좋은 방법일 것입니다! Java에서는 데이터가 상주해야 하는 위치, 즉 프로그램의 어느 부분이 어떤 데이터를 소유하고 해당 데이터를 효율적으로 공유할 수 있는지에 익숙해지는 것이 처음에는 다소 어려울 수 있습니다. 그러나 데이터가 코드를 통해 흐르는 방식에 대한 저항이 가장 적은 경로를 찾는 것이 결국 더 나은 Java 작성으로 이어질 것이라고 믿습니다.

우리가 다루어야 할 것이 훨씬 더 많습니다. 따라서 Java에서 오는 Rust에 대한 다음 모험과 함께 이번 달에 새로운 게시물을 기대하세요! 이것이 통찰력이 되었기를 바라며, 주저하지 말고 의견, 의견, 제안, 수정 사항, 불만 사항을 남겨주십시오…

https://wcgw.dev/posts/2023/rusty-java-2/#_where_did_we_get_so_far

728x90

+ Recent posts