현재 mac과 linux 를 사용하고 있습니다. 최근에서 linux 운영체계를 더 자주사용하고 있습니다. 사용하면서 blog 글을 linux 에서 작성해서 mac과 공유하는 문제가 발생했습니다.
저는 Mac에서 ㅣObsidian 을 사용해서 google drive 와 파일싱크를 통해서 저장하고 있었습니다. 그런데, linux에서는 공식적으로 지원하는 google drive앱이 없기 때문에, 3rd party앱으로 이를 해결해야 합니다.

여러가지 앱을 사용해 봤지만, 현재는 rclone 을 사용해서 해결하고 있습니다.
우선 rclone config 명령어를 통해서 웹하드를 연결해야 합니다. (구글드라이브 연결도 간단함)

rclone 을 통해서 드라이버 연결

현재는 GOOGLE DRIVE 와 DROPBOX가 연결 해놓은 상태입니다. NEW를 통해서 새로운 웹하드에 연결을 할 수 있습니다.
rclone v1.61.1 에서 지원하는 목록입니다.

$ rclone config
Current remotes:

Name                 Type
====                 ====
dropbox              dropbox
gDrive               drive

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> n

Enter name for new remote.
name> d

Option Storage.
Type of storage to configure.
Choose a number from below, or type in your own value.
 1 / 1Fichier
   \ (fichier)
 2 / Akamai NetStorage
   \ (netstorage)
 3 / Alias for an existing remote
   \ (alias)
 4 / Amazon Drive
   \ (amazon cloud drive)
 5 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, Ceph, China Mobile, Cloudflare, ArvanCloud, DigitalOcean, Dreamhost, Huawei OBS, IBM COS, IDrive e2, IONOS Cloud, Liara, Lyve Cloud, Minio, Netease, RackCorp, Scaleway, SeaweedFS, StackPath, Storj, Tencent COS, Qiniu and Wasabi
   \ (s3)
 6 / Backblaze B2
   \ (b2)
 7 / Better checksums for other remotes
   \ (hasher)
 8 / Box
   \ (box)
 9 / Cache a remote
   \ (cache)
10 / Citrix Sharefile
   \ (sharefile)
11 / Combine several remotes into one
   \ (combine)
12 / Compress a remote
   \ (compress)
13 / Dropbox
   \ (dropbox)
14 / Encrypt/Decrypt a remote
   \ (crypt)
15 / Enterprise File Fabric
   \ (filefabric)
16 / FTP
   \ (ftp)
17 / Google Cloud Storage (this is not Google Drive)
   \ (google cloud storage)
18 / Google Drive
   \ (drive)
19 / Google Photos
   \ (google photos)
20 / HTTP
   \ (http)
21 / Hadoop distributed file system
   \ (hdfs)
22 / HiDrive
   \ (hidrive)
23 / In memory object storage system.
   \ (memory)
24 / Internet Archive
   \ (internetarchive)
25 / Jottacloud
   \ (jottacloud)
26 / Koofr, Digi Storage and other Koofr-compatible storage providers
   \ (koofr)
27 / Local Disk
   \ (local)
28 / Mail.ru Cloud
   \ (mailru)
29 / Mega
   \ (mega)
30 / Microsoft Azure Blob Storage
   \ (azureblob)
31 / Microsoft OneDrive
   \ (onedrive)
32 / OpenDrive
   \ (opendrive)
33 / OpenStack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
   \ (swift)
34 / Oracle Cloud Infrastructure Object Storage
   \ (oracleobjectstorage)
35 / Pcloud
   \ (pcloud)
36 / Put.io
   \ (putio)
37 / QingCloud Object Storage
   \ (qingstor)
38 / SMB / CIFS
   \ (smb)
39 / SSH/SFTP
   \ (sftp)
40 / Sia Decentralized Cloud
   \ (sia)
41 / Storj Decentralized Cloud Storage
   \ (storj)
42 / Sugarsync
   \ (sugarsync)
43 / Transparently chunk/split large files
   \ (chunker)
44 / Union merges the contents of several upstream fs
   \ (union)
45 / Uptobox
   \ (uptobox)
46 / WebDAV
   \ (webdav)
47 / Yandex Disk
   \ (yandex)
48 / Zoho
   \ (zoho)
49 / premiumize.me
   \ (premiumizeme)
50 / seafile
   \ (seafile)
Storage> ^C⏎             

웹하드를 등록하는 부분은 간단한 부분이어서 따로 설명은 안 하려고합니다.

sync 하기

웹드라이브에서 파일과 LOCAL의 폴더를 동기화하고 싶을 때 사용합니다. 필요한 경우 파일 삭제를 포함하여 소스와 일치하도록 대상을 업데이트 합니다.

동기화시 삭제가 포함되므로 데이터 손실을 방지하기 위해 항상 --dry-run 또는 --interactive/-i 프랠그를 사용하여 동기하 작업을 먼저 테스트 하는 것이 좋습니다.

`-i`: interactive 모드를 사용하면 파일이 강제적으로 수정되는 것을 막고, 확인하면서 동기화할 수 있습니다.

파일을 원본에서 복사할 곳을 잘 설정하는 것이 중요합니다
$ rclone sync -i [원본 폴더] [목적지]

# google drive -----> local
$ mkdir -p ~/gdrive/[폴더명]
$ rclone sync -i mygdrive:/[폴더명] ~/gdrive/[폴더명]

# local ------> google drive
$ rclone sync -i ~/gdrive/[폴더명] mygdrive:/[폴더명]
  • --bwlimit=8.5M: 대역폭 속도를 8.5M으로 제한하여 Google에 부과하는 일일 최대업로드 한도에 도달하지 못하도록 합니다.
  • --progress: 복제/동기화 중인 파일이 완료될 때까지 남은 시간, 복제/동기화가 전송되는 속도를 보여주는 출력 합니다.

파일 조회하기

동기화 하기 전에 해당 웹하드에 어떤파일이 들어있는지 명령어를 통해서 조회 할수 있습니다. 굳이 웹을 통해서 조회하지 않아도 바로 조회할 수 있어 편합니다.

$ rclone ls mygdrive:
$ rclone lsd mygdrive:

mount 하기

저는 실시간으로 파일을 동기화해서 사용하고 싶기 때문에 위와 같이 파일을 sync 하는 것과는 다릅니다.

$ rclone mount gDrive:source_folder target_folder --allow-other --cache-db-purge --fast-list --poll-interval 10m

systemd 구성으로 자동 mount 하기

매번 명령어를 실행해서 동작하는 것을 systemd에 등록해서 자동 mount 하려고 합니다.

/etc/systemd/system/gdrive.service 파일을 생성합니다.

[Unit]
Description=rclone for gdrive_mount
AssertPathIsDirectory=/home/leaf/target_folder
After=networking.service

[Service]
Type=simple
ExecStart=rclone mount --config=/home/leaf/.config/rclone/rclone.conf gdrive_source_folder: /home/leaf/target_folder --allow-other --cache-db-purge --fast-list --poll-interval 10m
ExecStop=/bin/fusermount -u /home/leaf/target_folder
Restart=always
RestartSec=10

[Install]
WantedBy=default.target
$ systemctl enable gdrive.service
$ systemctl start gdrive.service
반응형

현재 리눅스에서 지원하는 키보드 세팅 확인

$ grep -E "(ctrl|caps)" /usr/share/X11/xkb/rule/base.lst
$ setxkbmap -option ctrl:swapcaps

참조: https://wiki.archlinux.org/title/xmodmap

The following example modifies CapsLock to Control, and Shift+CapsLock to CapsLock:

  • CapsLock -> Control
  • Shif t+ CapsLoc ->: CapsLock

~/.Xmodmap 파일수정

clear lock
clear control
add control = Caps_Lock Control_L Control_R
keycode 66 = Control_L Caps_Lock NoSymbol NoSymbol
반응형

created: <% tp.file.creation_date() %>
tag: #독서
title: 장사의신
author:
category: [사업,요식업]
publish_date:
cover_url: https://contents.kyobobook.co.kr/sih/fit-in/458x0/pdt/9788934985068.jpg
status:
start_read_date:
finish_read_date:
my_rate:
book_note:


<% tp.file.title %>

자신의 가게에서 일하는 알바생들을 졸업시키는 일을 하고 있다. [우노 타케시]는 라쿠코페레이션이라는 기업을 운영하면서 여러가지 특색을 가진 음식점을 운영하고 있다. 특이한 점은 여기에서 일하는 사람을 성장, 독립시켜 다른 요식업의 사장들을 배출하고 있다는 점이다.
사람은 자신이 가지고 있는 기술, 경험을 남에게 가르켜주려고 하지않는다. 생계수단이 이 기술에서 비롯되기 때문이다. 그렇기 때문에 다른 사람에 기술을 전수하지 않음으로 해서 자신의 위치를 유지할 수 있다. 경험에서 얻어지는 지혜와 지식은 돈으로 살수 없는 가치를 지니고 있다. 이 것을 아무런 조건없이 다른사람에게 전달한다는 것은 큰 배포에서 오는 것이 아닐까.
우노 타케시는 떠오른 경험을 여과없이 자식들(직원들)에게 전수하고, 떠오르는 상품에 관한 아이디어를 공유한다. 이 아이디어로 새로운 메뉴를 그대로 사용하는 이도 있고, 이를 더 발전시켜서 적용시키는 사람도 있다.

아이디어를 생각나게 하는 경험

여기서 중요한 점은 그의 생각은 꾸준히 새로운 것을 떠올린 다른 점이다. 다양한 아이디어를 떠오르게 하는 기반이 무엇일까 생각해 보면, 고객과의 대화였다. 한번 더 대화하기 위한 접객에 방법에 대한 고민은 다양한 생각의 끈으로 이뤄졌다.
물건을 하나 팔려고 해도 고객과의 대화가 반드시 이뤄진다. 자연스럽게 대화하기 위한 계기를 만들어가는 방법이 아이디어를 만들어 주었고, 지속적인 발전을 만들어 주었다.

미래를 보여줄 수 있는 본보기

성공을 할 수 있다는 본보기를 보여주는 것은 큰 설득력이 된다. 캐나다에 있는 집. 별장. 이런 것들은 직원들로 하여금 얼마나 성장할 수 있는지에 대한 큰 결심, 마음을 만들어 준다.
솔선수범도 해야 한다. 점장이 되고 난 뒤에 청소, 장보기, 접객... 은 직원들로 하여금 따라올 수 있는 믿음있는 선배가 된다.

기억하는 차트

  1. 제대로 된 가게를 보고 다녀라.
  2. 아이디어는 바로 실행할 수 없으면 의미가 없다.
  3. 돈이 필요 없는 아이디어 수집법
  4. 인적이 드문 곳에 가게를 열어라.
  5. 평범한 메뉴를 특별하게 만드는 방법
  6. 불황에 강한, 알기쉬운 간판 메뉴
  7. 손님을 기쁘게 하는 방법
  8. 키노시타 토키치로의 “짚신 이야기”

종평

책은 개인사업, 특히 요식업을 하는 사람들에게 필요한 내용들을 담고 있다. 하지만, 일반 생활에서도 충분히 적용할 수 있는 아이디어들이 있고, 사람들을 대하는 사고의 방식은 충분히 배울 가치가 있다.

반응형

최근에 사회 심리학에 대한 관심이 높아졌습니다. 간이 나면 YOUTUBE 를 통해서 공부했고, 현재 자신에 대해 정리하고, 삶에 적용하려고 하고 있습니다. 책을 읽고 난 지금은 생각나지 않지만, 읽어야 하는 책으로 소개가 된 것을 보고, 제목이 마음이 동하여 읽게 되었습니다.

처음 몇장을 읽고 몇가지 인상적인 느낌이 있습니다. 한자표기가 되어 있는 책은 근래 접하기 힘들었는데, 생소했습니다. 예를 들어 내용 중에 중년의 삶은 사춘기(思春期)와 유사하다며 사추기(思秋期)라는 재미있는 표현을 사용합니다.
그리고 저자가 교수이기에 참조 교과서의 향이 나기도 합니다. 불편한 느낌은 아니고 자연스러운 느낌입니다. 삶에 대한 이야기는 주변의 이야기 처럼 익숙하게 다가오고, 편하게 읽을 수 있는 느낌이었습니다.

책이 조금은 졸린 느낌이 있어서 장사의신이라는 책과 동시에 읽었습니다.

사추기(思秋期): 중장년 층이 새로이 정신적, 육체적으로 변화를 겪는 시기를 이르는 말

시작

“본보기를 따라 사는 사람에게는 생명력이 없다. 당신이 당신의 삶을 살지 않는다면, 누가 당신의 삶을 살겠는가? 그러니 당신 자신의 삷을 살아야 한다. -- 카를 융

카를 융은 중년이 넘어서야 비로소 사는 것이 무엇인지 그 깊은 맛을 알 수 있고, 비로소 자기실현을 할 수 있다고 언급했습니다. 중년기는 말 그대로 '나로 살아야 할'시기라는 점입니다.
이제 중년이라는 나이로 접어들게 되는 저는 삶에 대해서 반복적으로 의문을 가져야 한다고 생각합니다. 과거와 지금의 시기가 다른 점은 과거에는 미래를 위해서 살아갔던 것 같습니다. 지금은, 과거를 곱씹으며, 미래를 조심스럽게 나아가고 있는 것 같습니다.
성숙이라는 것은 경험을 통해서만 이뤄낼 수 있는 것으로 보입니다. 이 경험을 이 책을 통해, 교수의 상담내용을 통해서 간접체험을 하고 성숙해져 가는데에 데움이 될 수 있을 것 같습니다.

중년이란?

고령화 사회가 되었기 때문에? 중년기라는 말이 대중적으로 익숙해져갔습니다. 아버지가 되어 그 자리가 익숙해져가는 시기이며, 자신을 포기하고, 가족과 자식들을 위해서 한없이 헌신하는 시기였습니다. '젊은이'도 아니고 '늙은이'도 아닌 과도기적인 시기에 자신을 잃어버리지 않기 위해서는 자신에 대해서 아끼며 살아가야 합니다. 그리고, '노년기' 전에 낼 수 있는 마지막 기회을 잡을 수 있습니다.

“오늘부터는 나를 아껴야 한다”

목차

  1. 나를 아껴야 한다.
  2. 중년에는 자기실현을 하기 가장 좋다
  3. 내 인생의 목적은 무엇인가
  4. 사랑이 사람을 살게 한다.
  5. 나를 아끼면 과거도 변한다

중년의 장점과 중년기에 자신이 할 수 있는 일에 대한 정의. 과거보다 나아진 점은 경험을 통한 대화방식이겠다. 원만한 의사소통 능력은 어렸을 적에는 급하기만 자신을 여유롭게 가져간다.

과거와 미래를 동시에 볼 수 있다. 모든 분야에 대해서 급속한 발전 청년기에 이뤄낸다. 중년기에는 이 성장을 유지하고 노년기에는 쇠퇴기로 접어든다. 삶은 성장 - 유지 - 퇴보 순으로 진행 된다. 현재 나는 성장과 유지하는 단계로 판단하고 있다. 아직은 꾸준히 자기발전에 노력을 하고 있으며, 이뤄 낸 것이 아직 없기 때문이다.

내가 동의하는 철학은 가정이 화목해야 성공할 수 있는 믿음이다. 내실이 튼튼하다면, 하는 일에 대해서 집중을 할 수 있기 때문이다. 그렇기에 아내를 존경합니다.

주요단어

  1. 젊음과 늙음이 교차하는 시기
  2. 부모와 자식 간의 관계
  3. 줄탁동시
  4. 사소한 감정을 나누자
  5. 잘못을 인정할 때 가족관계는 돈독해 진다
  6. 권위적인 삶, 권의주의적인 삶
  7. 직관적인 문제해결능력
  8. 인생의 절정기
  9. 오뚝이이 같은 재도전 할 수 있게 만드는 자존감
  10. 제대로 된 사과가 필요하다
  11. 상대에게 대한 공감
  12. 봉사 .... ?
  13. 생산성(generativity) ... 자식이 공부 잘하는 사람이 제일 목소리가 크다
  14. 사랑하고 일하라.
  15. 친밀함의 상징
  16. 신체를 통한 즐거움,섹스리스, 유혹을 물리치다
  17. 젊음을 확인할 수 있는 방법은 이성을 통해서 이다
  18. 사춘기, 사추기
  19. 가족과 보내는 하루 평균시간 13분
  20. 비난, 경멸, 방어, 의사방해
  21. 성숙한 부모, 스위트홈
  22. 중년에 부모와 사이가 나빠지는 이유는 부모와 자신과의 분리가 필요하다
  23. 소문만복래
  24. 좋아서 하는 행동, 자발적 행동
  25. 잘 놀아야 한다
  26. 놀기 위해 일하다.

책을 다 읽고 난 뒤의 느낌은 이해는 하는데 남아있는 것은 없는 같았습니다. 그래서 다시 한번 읽고서 내용을 정리하려고 했습니다만, 정독하는 것 보다는 책을 한장씩 넘겨가며 주요단어를 수집하기로 했습니다.

#독서

반응형

#초보자 #생산력

본 글은 아래 3가지 내용을 담고 있습니다.

  • 기술 조언에 대한 중요한 맥락과 동기
  • 기술 조언
  • 추천 읽을거리 시작하기에 좋은 고품질 책과 블로그에 대한 링크

주니어를 위한 일반적인 조언

1. 코드가 포인트가 아니다

개발자로서 우리는 코드 작성을 좋아합니다. 우리 대부분은 명확하고 멋진 작업을 원하고, 다른 세계에 관심을 기울이지 않고, 풀 수 있는 재미있는 기술 퍼즐입니다.

올바른 문제를 해결하고 있는지 확인하기 위해 합리적인 노력을 해야 합니다. Peter Drucker의 말을 인용하자면: 전혀 하지 말아야 할 일을 효율적으로 하는 것만큼 쓸모없는 것은 없습니다. 일반적으로개발 초기에 실제 사용자에게 지속적으로 피드백을 수집합니다.

무엇이 중요한 문제인가?
올바른 일을 하는 것과 일을 제대로 하는 것 사이에 놓인 효과와 효율성의 혼란에서 모든 문제는 비롯된다. 확실한 것은 하지 않아도 될 일을 효율적으로 하는 것 만큼 쓸모없는 일은 없다는 것이다.

  • 피터 드러커

소프트워어 개발은 비용이 많이 들고, 실제 프로젝트의 대부분의 유지보수 비용으로 사용됩니다. 이를 시용자/비즈니스 결과라는 목표와 결합하게 되면, 좋은 코드는 대부분 없는 경우가 많습니다
소프트웨어 개발은 유지 관리 비용이 들어가는 실제 프로젝트의 노력의 대부분과 함께 비용이 많이 듭니다. 이것을 사용자/비즈니스 결과라는 목표와 결합하면 최상의 코드는 코드가 없는 경우가 많습니다. Bill Gates의 말을 인용하자면 "코드로 프로그래밍 진행 상황을 측정하는 것은 항공기 제작 진행 상황을 무게로 측정하는 것과 같습니다."

2. 소프트웨어 설계 문제

개발 경력의 첫 5년 동안 저는 소프트웨어 설계가 소프트웨어 설계자나 특별한 역할을 맡은 다른 사람들을 위한 것이라고 생각했습니다. 나는 "일을 끝내는 것"에 집중했고, 소프트웨어 디자인과 테스트 작성과 같은 관행이 방해가 된다고 생각했습니다. 내 코드는 작동했고, 많은 일을 하고 있었습니다. 많은 일을 하고 있다고 생각했습니다.

그런 다음 Robert C. Martin 의 Clean Code 를 읽었습니다 . 이 책은 소프트웨어 디자인에 관심을 갖도록 동기를 부여하고, 예제와 많은 기술적 발견을 포함하고 있습니다. 가장 개념적인 테이크어웨이는 "빨리 가는 유일한 길은 잘 가는 것"입니다. 즉, 엉망으로 만들면 속도가 느려집니다.

잘 설계된 깨끗한 코드를 작성하는 방법을 배우는 것은 물론 시간과 노력이 필요합니다. 그리고 시작하면 속도가 느려지고 실수를 하게 됩니다. 단순한 것은 쉽지 않습니다.

3. 모범 사례 사용

테스트 작성은 유익한 경향이 있습니다. 예외가 있지만 대부분의 경우 자동화된 테스트를 작성하는 것이 좋습니다. 테스트 작성은 모범 사례의 한 예입니다.

테스트 작성이 처음이라면 모범 사례를 따르고 모든 것에 대한 테스트를 작성하십시오. 시작할 때 맹목적으로 모범 사례를 따르는 것이 자신의 미숙한 판단을 따르는 것보다 낫습니다 . 시간이 지남에 따라 테스트를 효과적으로 작성하는 방법을 배우고, 테스트를 작성하는 것이 가치가 없는 상황과 엉망인 상황을 구분할 수 있게 될 것입니다. 또한 디버깅 세션의 감소와 테스트에서 활성화된 걱정 없는 리팩토링을 경험함으로써 테스트가 보다 본능적인 수준으로 가져오는 가치를 이해하기 시작할 것입니다. 판단력을 개발한 후에는 모범 사례를 초월할 수 있습니다 .

이 조언은 당신이 2학년인 모든 영역의 모범 사례에 적용됩니다. 자동화된 테스트는 하나의 예일 뿐입니다.

한 가지 큰 문제는 합리적인 모범 사례와 무의미하거나 심지어는 역효과를 낳는 것과 구별하기가 쉽지 않다는 것입니다. 이것은 대부분의 기존 코드가 엉망이고 "숙련된" 및 "선배" 개발자를 포함하여 대부분의 개발자가 소프트웨어 설계 기본 사항을 모르기 때문에 더 복잡해집니다. 이것은 좋은 멘토를 갖는 것을 매우 가치있게 만듭니다. 그것을 제외하고 내 자신의 경험에 기반한 조언 중 하나는 귀하의 언어 또는 프레임워크 커뮤니티에 특정한 모범 사례를 주의하라는 것입니다. 수십 년 동안 주변에 있었던 상록 조언을 찾으십시오.

주니어를 위한 기술 조언

1. 테스트 코드 작성

자동화된 테스트를 작성합니다. TDD( Test Driven Development ) 를 통해 코드보다 먼저 테스트를 작성할 수 있습니다. 이렇게 하면 반복 가능한 방식으로 코드가 올바른지 쉽게 확인할 수 있으므로 수동으로 재시도하거나 세션을 디버깅하지 않아도 됩니다.

디버그를 실행합니다.

아마도 중요한 것은 테스트를 통해 코드를 리팩토링할 수 있는 안전망을 얻을 수 있다는 것입니다. 그리고 코드를 깨끗하게 유지하려면, 지속적인 리팩토링이 필요합니다. 신뢰할 수 있는 테스트 모음이 없으면 코드가 썩을 가능성이 훨씬 더 높아집니다.

코드 재사용을 위해 상속을 사용하거나 정적 함수를 사용할 때와 같이 코드 디자인이 좋지 않으면 테스트 작성이 어렵습니다. 반면에 전역 종속성이 없는 SOLID 클래스가 있다면, 멋진 테스트를 작성하는 것이 그렇게 어렵지 않습니다.

잘못 작성된 테스트는 속도를 늦추기 때문에 테스트 디자인이 중요합니다. 테스트 중인 코드의 구현 세부 사항이나 시스템 구조에 테스트를 바인딩하지 마십시오. Mocks의 남용을 피하고 더 나은 Test Doubles를 작성 하십시오 .

2. 코드 재사용을 위해 상속을 사용하지 마십시오

이것은 "모범 사례 사용" 섹션을 염두에 두는 모범 사례 중 하나입니다. 내 조언: 시작할 때 코드 재사용을 위해 상속을 전혀 사용하지 마십시오. 그것은 거의 올바른 호출이 아니며 많은 피해를 줄 수 있습니다. 상속보다 구성을 선호 합니다.

3. 객체 지향 코드 작성

STUPID 가 아닌 SOLID 코드를 작성 하십시오. 이러한 원칙과 반패턴을 이해하는 데는 많은 가치가 있습니다.

실제로 개체를 만듭니다. 정적 메서드만 있는 클래스는 OO가 아닙니다. 정적 코드를 완전히 사용하지 마십시오.

참조: SOLID에 대한 나의 방어 .

4. 기능 코드 작성

( 함수형 프로그래밍 은 구조 프로그래밍 과 혼동되어서는 안 됩니다 .)

이 요점은 기능적 언어로 완전히 전환하는 것에 관한 것이 아닙니다. OO 언어에서 기능적 스타일을 사용하면 이점을 얻을 수 있습니다. 특히 변경 가능한 상태를 최소화 하고 함수에서 한 가지 작업을 수행합니다.

5. 정보에 입각한 복제 사용

많은 양의 코드 덩어리를 여러 위치에 복사하여 붙여넣는 것은 현명하지 않습니다. 자존심이 강한 개발자라면 누구나 곧 이것을 배우고 DRY( Don't Repeat Yourself ) 형식을 따르기 시작합니다. 불행히도, 의도적으로 DRY를 추구하면 과도한 엔지니어링과 우발적인 복잡성으로 이어지는 경우가 많습니다. DRY의 대응물인 WET(Write Everything Twice)가 여기에 해당합니다. WET의 기본 개념은 중복이 세 번째 발생하는 경우에만 중복을 제거하는 것입니다.

6. 유형, 이름 및 설명

자체 문서화 코드를 작성하고 주석을 피하십시오.

설명을 작성할 때마다 찡그린 표정을 짓고, 표현력의 실패를 느껴야 합니다. -- 로버트 C. 마틴

코멘트는 거짓말을 할 수 있기 때문에 위험합니다. 코드는 주석이 업데이트되지 않고 변경될 수 있습니다. 주석 바로 아래에 새 코드를 추가할 수 있습니다. 댓글이 처음부터 잘못되었거나 정확하지 않을 수 있습니다. 이런 일이 발생하면 댓글은 쓸모없게 될 뿐만 아니라 오해의 소지가 있습니다.

자체 문서화 코드를 작성하려면:

  • 기능에서 한 가지 작업 수행
    • 함수에서 한 가지 작업을 수행하여 명확한 이름을 지정할 수 있습니다.
    • 주석을 추가하여 함수의 다른 섹션이 수행하는 작업을 설명할 필요가 있을까요? 대신, 각 섹션을 고유한 이름의 함수로 추출하십시오.
    • "추출할 때까지 추출": 의미 있는 기능을 추출할 수 있다면 아마도 그렇게 해야 할 것입니다. 작은 기능을 두려워하지 마십시오.
    • 명령 쿼리 분리
    • 클래스 에 대한 단일 책임 원칙 (SOLID의 S)과 유사
  • 상태 최소화
  • 유형을 사용하십시오 . 코드를 실행하는 테스트 스위트와 결합하여 진실을 말하는 유형에 의존할 수 있습니다.
  • 혼합 유형을 피하십시오 . 정수, 부울 또는 문자열이 될 수 있는 매개변수 또는 반환 값을 피하십시오. 이것은 한 가지만 수행하는 집중 함수를 작성하는 경우 자연스럽게 발생합니다.
  • 테스트 작성 . 잘 작성되고 포괄적인 테스트 스위트는 프로덕션 코드가 어떻게 사용되며 어떻게 작동하는지 보여줍니다.

Robert C. Martin의 Clean Code 에는 이름 지정 및 주석에 대한 몇 가지 좋은 경험 법칙이 있습니다.

주니어 추천도서

서적

반응형

GitHub의 오픈 소스 프로젝트는 개발자가 기술 개발에 기여하면서 배우는 가장 좋은 방법일 것입니다. AI/ML 분야도 다르지 않습니다. 점점 더 많은 사람들이 AI/ML 모델을 구축하는 데 관심을 갖게 되었고, 몇몇 대형 기술 회사도 개발 발전을 위해 코드를 공개했습니다.

다음은 시도해볼 수 있는 이러한 인기 있는 오픈 소스 프로젝트 12개의 목록입니다!

TensorFlow

텐서플로 또는 텐서플로우는 다양한 작업에대해 데이터 흐름 프로그래밍을 위한 오픈소스 소프트웨어 라이브러리입니다. 심볼릭 수학 라이브러리이자, 인공 신경망같은 기계 학습 응용프로그램 및 딥러닝에도 사용된다. 위키백과

텐서플로(TensorFlow) 또는 텐서플로우는 다양한 작업에대해 데이터 흐름 프로그래밍을 위한 오픈소스 소프트웨어 라이브러리입니다. 심볼릭 수학 라이브러리이자, 인공 신경망같은 기계 학습 응용프로그램 및 딥러닝(deep Learning)에도 사용됩니다.

TensorFlow 플랫폼은 데이터 자동화, 모델 추적 및 재교육, 성능 모니터링에 사용됩니다. Google Brain 팀에서 개발했으며 약 150,000명의 활성 기여자가 있습니다. 이 모델의 유연성으로 인해 프로젝트에 포함하는 개발자 서클에서 매우 인기가 있습니다.

GitHub 리포지토리를 사용하면 사용자가 편의를 위해 클라우드 또는 모바일 장치에서 빌드할 수 있습니다. 이 알고리즘은 이미지 분류, 음성 인식, 분할 등과 같은 많은 컴퓨터 비전 기반 응용 프로그램에 사용됩니다.

OpenCV

OpenCV은 실시간 컴퓨터 비전을 목적으로 한 프로그래밍 라이브러리입니다. 원래는 인텔이 개발하였다. 실시간 이미지 프로세싱에 중점을 둔 라이브러리입니다. 인텔 CPU에서 사용되는 경우 속도의 향상을 볼 수 있는 IPP를 지원합니다. 위키백과

Computer Vision은 아마도 로봇에서 자율주행 차량에 이르기까지 인공 지능을 위한 가장 수요가 많은 도구일 것입니다. OpenCV는 기계 학습 작업에서 컴퓨터 비전을 사용하기 위한 대규모 오픈 소스 리포지토리를 제공하며 Python 개발자가 사용할 수 있습니다.

저장소에는 컴퓨터 비전과 관련된 2500개 이상의 알고리즘이 있으며 Google, IBM, Intel과 같은 빅 테크 회사는 많은 개발 프로젝트에서 이를 사용합니다.

React-Native

리액트 네이티브는 페이스북이 개발한 오픈 소스 모바일 애플리케이션 프레임워크입니다. 안드로이드, iOS, 웹, UWP용 애플리케이션을 개발하기 위해 사용되며, 개발자들이 네이티브 플랫폼 기능과 더불어 리액트를 사용할 수 있게 합니다. 완전하지 않은 Qt 포팅 또한 존재합니다. 위키백과

Facebook, Twitter 및 Pinterest를 포함한 거의 모든 소셜 미디어 플랫폼에서 사용됩니다. 프레임워크를 통해 개발자는 플n랫폼에서 기본 앱을 빌드하고, 기본 UI 컨트롤에 대한 전체 액세스 권한을 얻을 수 있습니다.

GitHub 커뮤니티에는 100,000개 이상의 별이 있으며 기여자가 활발하게 증가하고 있습니다. 플랫폼에는 개발자가 쉽게 이해하고 수정할 수 있는 선언적 보기가 있습니다.

DALL-E

DALL-E와 DALL-E 2는 오픈AI가 자연어 서술로부터 디지털 이미지를 생성하기 위해 개발한 기계 학습 모델입니다. DALL-E는 2021년 1월 블로그 게시물에서 오픈AI에 의해 공개되었으며, 이미지 생성을 위해 개조된 GPT-3 버전을 사용합니다.

text-to-image 모델이 화제가 되고 있으며 DALL-E가 GitHub에 코드를 공개함에 따라 가능성은 이제 무한합니다. 기계 학습 모델이 어떻게 작동하는지 알아보려면 DALL-E에 단어를 연결하고 기계가 "생각하는" 방식을 확인하세요.

GitHub의 오픈 소스 프로젝트는 VAE를 위해 DALL-E에서 사용되는 공식 PyTorch 패키지이지만 패키지에는 이미지 생성에 사용되는 변환기가 포함되어 있지 않습니다.

VAE는 Autoencoder로 데이터의 latent space를 찾으면서, 동시에 variational inference를 통해 latent space를 normal distribution을 가정한 prior로 regularization 합니다.

YOLOv7

YOLO는 You Only Look Once의 약자로써 이미지 및 동영상 탐지에 사용되는 딥러닝 모델입니다.

자율 차량, 로봇 또는 기타 비전 기반 장치와 관련하여 물체 감지는 시스템의 핵심 부분 중 하나입니다. 가장 빠르고 정확한 물체 감지 알고리즘 중 하나인 YOLOv7은 완벽한 솔루션을 제공합니다.

GitHub 리포지토리에는 개발자가 프로젝트에서 구현하고 이미지 컬렉션을 제공하여 모델을 교육할 수 있는 패키지가 포함되어 있으며 모델은 탐지 프로세스를 시작합니다.

쿠버네티스는 컨테이너화된 애플리케이션의 자동 디플로이, 스케일링 등을 제공하는 관리시스템으로, 오픈 소스 기반입니다. 원래 구글에 의해 설계되었고 현재 리눅스 재단에 의해 관리되고 있습니다. 위키백과

K8s는 개발자가 모든 플랫폼에서 컨테이너화된 앱을 관리할 수 있도록 Google에서 개발했습니다. 자동화된 시스템은 앱의 확장, 개발 및 관리를 지원합니다.

GitHub에 70,000개 이상의 별이 있는 Google에서 구축한 가장 인기 있는 저장소 중 하나입니다. 컨테이너 패키지 서비스의 글로벌 리더인 K8s는 CNCF(Cloud Native Computing Foundation)에서 호스팅합니다.

Flutter

플러터는 구글이 출시한 오픈 소스 크로스 플랫폼 GUI 애플리케이션 프레임워크입니다. 안드로이드, iOS, 윈도우즈, 리눅스 및 웹용 애플리케이션과 구글 퓨시아용 앱의 주된 소스코드로 사용된다. 위키백과

Google에서 개발한 또 다른 Flutter는 개발자가 인터페이스 툴킷을 사용하여 단일 코드베이스에서 앱을 빌드할 수 있게 해주는 소프트웨어 개발 키트(SDK)입니다. Skia에 의해 구동되므로 생성된 앱은 PC, 웹 및 모바일 플랫폼과 호환됩니다.

GitHub의 100,000 별 커뮤니티는 witbiOS와 함께 Android 및 Chromium 기반 애플리케이션과 호환되며 코드를 엉망으로 만들지 않고 그래픽, 텍스트 및 비디오 오버레이를 매끄럽게 통합하는 데 효과적입니다.

Jenkins

젠킨스는 소프트웨어 개발 시 지속적 통합 서비스를 제공하는 툴입니다. 다수의 개발자들이 하나의 프로그램을 개발할 때 버전 충돌을 방지하기 위해 각자 작업한 내용을 공유 영역에 있는 Git등의 저장소에 빈번히 업로드함으로써 지속적 통합이 가능하도록 해 준다. MIT 라이선스를 따른다. 위키백과

이 Java 기반 자동화 서버에는 거의 모든 것을 자동화하기 위한 1800개 이상의 플러그인이 있습니다. 사용하기 쉬운 프레임워크이며 모든 언어로 조정 가능한 지속적인 통합 및 전달 환경을 제공하는 것과 함께 애플리케이션을 빌드, 테스트 및 배포하는 데 유용합니다.

Jenkins는 정적 코드 분석 및 모델의 버그 감지에도 유용합니다. 이 서버를 통해 개발자는 지루하고 반복적인 작업을 실행 및 자동화하고 기계가 할 수 없는 작업에 집중할 수 있습니다.

Ansible

Ansible은 오픈 소스 소프트웨어 프로비저닝, 구성 관리, 애플리케이션 전개 도구입니다. 수많은 유닉스 계열 시스템에서 실행되며 유닉스 계열 운영 체제 및 마이크로소프트 윈도우의 구성이 가능하다. 시스템 구성을 기술하기 위해 자체 선언형 언어를 포함하고 있습니다. 위키백과

2016년 RedHat에서 시작한 Ansible은 개발자가 시스템을 구성하고, 네트워크를 관리하고, 소프트웨어를 배포할 수 있는 자동화 플랫폼입니다. 설정이 매우 간단하고 학습 곡선이 거의 없기 때문에 많은 관심과 기여를 받았습니다.

약 55,000개의 별이 있는 Ansible은 접근 방식이 일반 영어와 매우 유사하기 때문에 적극적으로 기여 및 업데이트를 받고 있습니다.

PredictionIO

Apache PredictionIO®는 개발자와 데이터 과학자가 모든 기계 학습 작업에 대한 예측 엔진을 생성할 수 있도록 최첨단 오픈 소스 스택 위에 구축된 오픈 소스 기계 학습 서버 입니다. 다음을 수행할 수 있습니다.

  • 사용자 지정 가능한 템플릿 을 사용하여 프로덕션 환경에서 엔진을 웹 서비스로 신속하게 구축 및 배포합니다 .
  • 웹 서비스로 배포되면 실시간 으로 동적 쿼리에 응답합니다 .
  • 여러 엔진 변형을 체계적으로 평가하고 조정합니다.
  • 포괄적인 예측 분석을 위해 여러 플랫폼의 데이터를 일괄 또는 실시간으로 통합합니다.
  • 체계적인 프로세스와 사전 구축된 평가 수단으로 머신 러닝 모델링 속도를 높입니다.
  • Spark MLLib 및 OpenNLP와 같은 기계 학습 및 데이터 처리 라이브러리 지원
  • 고유한 기계 학습 모델을 구현하고 이를 엔진에 원활하게 통합합니다.
  • 데이터 인프라 관리를 단순화합니다.

알고리즘 배포, 이벤트 수집 및 평가, 예측 결과 쿼리를 지원하는 오픈 소스 ML 프레임워크입니다. HBase, Hadoop, Spark 및 Elasticsearch를 기반으로 하며 기계 학습 프로젝트를 위한 예측 엔진을 생성합니다.

이 프로젝트는 GitHub에 12,000개 이상의 별을 가지고 있으며 REST API를 통해 예측 결과를 생성합니다.

LightGBM

영어에서 번역됨-LightGBM은 Light Gradient-Boosting Machine의 약자로, 원래 Microsoft에서 개발한 머신 러닝을 위한 무료 오픈 소스 분산 그래디언트 부스팅 프레임워크입니다. 위키백과(영어)

의사 결정 트리 알고리즘을 기반으로 하는 가장 빠른 고성능 그래디언트 부스팅 프레임워크인 LightGBM은 주로 다른 기계 학습 작업 중에서 분류, 순위 지정에 사용됩니다. 여러 GPU로 대규모 데이터 및 병렬 학습을 지원하므로 다른 모든 경쟁자보다 매력적입니다.

Microsoft에서 개발한 LightGBM은 GitHub에 약 14,000개의 별을 가지고 있으며 개발자로부터 적극적으로 기여를 받고 있습니다.

ElasticSearch

일래스틱서치는 루씬 기반의 검색 엔진입니다. HTTP 웹 인터페이스와 스키마에서 자유로운 JSON 문서와 함께 분산 멀티테넌트 지원 전문 검색 엔진을 제공한다. 일래스틱서치는 자바로 개발되어 있으며 아파치 라이선스 조항에 의거하여 오픈 소스로 출시되어 있습니다. 위키백과

이 오픈 소스 프로젝트는 대용량 데이터를 실시간으로 분석, 검색 및 저장합니다. 이는 로그, 메트릭, 엔드포인트 보안, 검색 백엔드 및 애플리케이션 모니터링과 같은 데이터 관리가 필요한 프로젝트에 통합될 수 있습니다.

60,000개 이상의 별을 보유한 Elasticsearch는 개발자가 프로젝트 내에서 다양한 검색 엔진의 백엔드를 구축하고 개선할 수 있도록 해왔습니다.

반응형

재미가 있어서 하루만에 글을 다 읽었습니다. 주식에 대한 자세한 설명보다는 저자의 경험에 대한 개념설명 정도로 생각하고 읽을 수 있습니다. 파이어족이 되기 위한 입문서로 추천합니다.

경제적 자유를 찾는 현금 흐름을 완성하는 세가지

  1. 직장 등 노동을 통한 돈을 벌어야 한다.
  2. 그 돈을 아껴서 모음
  3. 돈을 불린다
  4. 투자의 세가지 요소
  5. 복리의 마법
    수익은 % 를 통해서 이뤄진다. 복리를 누리기 위해서는 여기서 발생한 수익에 대해서 다시 재투자가 되어야 합니다.
  6. 인플레이션
    소득, 대출, 투자자산의 증가에 의해서 통화량이 늘어나며, 현금의 가치는 하락하게 됩니다. 그렇기 때문에 주식이나 부동산 같은 자산의 가격도 상승한다는 것을 알 수 있습니다.
  7. 레버리지(지렛대)
    비싼 자산을 그보다 작은 돈을로 살 수 있는 방법 = 대출
    주식에서도 증거금률을 이용해서 1억원어치 주식을 2천억에 살수 있습니다. (높은 리스크)

읽지 않는 주식 투자법

주식투자를 '하는 것'과 '잘 하는 것'은 아주 다르다.

인간의 욕망은 주식투자에 안 맞에 설계되어 있으며, 감정이 배제 되어야 이길 수 있는 싸움이 된다. 그렇기 때문에 자신만의 시스템을 만들어 이성적인 선택을 해야 합니다.

주식에 대해서 알아야 할 지식

아래 용어에 대한 지식도 없는 투자는 초보 투자자를 벗어날 수 없다.

PER. PBR. PSR. PCR. PEG. ROE. ROA. 배당 성향. 최근 결산일, 여업이익, 부채

토스에서는 주식정보에서 설명을 확인할 수 있다. 하지만, 어떻게 활용하고 수치를 이용할지는 직접학습하고, 추가적인 공부를 해야 한다.

사업보고서 재무재표

달러와 주식으로 만드는 무한 수익 시스템

  • 투자를 도박처럼 하면 돈을 잃는다

투자는 손실난 주식에 대해서 실현하지 않으면 평가손실일 뿐 손실로 확정 되는 것은 아닙니다. 그리고 얼마든지 투자 할 수 있습니다. 투자는 값이 떨어지더라도 수익을 실행하지 않으면 손실이 확정되지 않기 때문입니다.
부자 대상의 가치가 완전히 사라지지 않는시앙 역전시킬 수 있는 기회가 있습니다.

달러 투자와 국내 주식 투자의 병행

해외 주식을 구매하는 것은 달러상승과 주식수익 두가지를 한꺼번에 가져갈 수 있습니다.
보통 원달러 환율이 상승하면 국내주식은 하락합니다. 이유는 국내 주식시장이 외국 투자자의 포지션에 영향을 받는 경우가 많기 때문이다.

“더 얻는 것보다 덜 잃는게 낫습니다.”

“달러 가치가 떨어지면 사고, 달러로 수익이 나면 파세요.”

달러 투자를 안 하면 손해인 이유 세가지

  1. 세계에서 사용하는 기축 통화
  2. 모든 투자 대상 중 거래 비용이 가장 낮다.
  3. 기회비용이 발생하지 않는다.

변동성과 배당 수익을 이용한는 주식 시스템

“틀린 질문만 하니까 맞는 답이 나올 수가 없다”

“언제 사야할까” -> “어떻게 해야 싸게 살 수 있을까?”

유사대답은 쌀때 사는 것 뿐입니다. 쌀때가 명확하지 않습니다. 누구도 정확하게 파악할 수 없기 때문이니다. 정량화 할 수 있는 미래 가치까지 따져야 하므로 가치를 정확하게 파악한다는 것은 불가능한 일에 가깝습니다.
그렇기 때문에 나눠사는 것이 이를 해결해 줄 수 있습니다.

워렌 버핏 “잘 아는 종목에 장기 투자 하라. 자신이 없다면, 인덱스 펀드에 분할 투자 하라.”

배당주

미국주식은 한국과는 다르게 다양한 배당확정일자를 가지고 있습니다. 월마다 배당을 해 주는 주식도 있고, 또는 분기마다, 년마다 다양한 배당 방식과 배당금을 가지고 있습니다.

  • A주식: 1,4,7,10 월에 배당금 지급
  • B주식: 2,5,8,11 월에 배당금 지급
  • C주식: 3,6,9,12 월에 배당금 지급
  • 매월 배당금을 받는 주식

장기 투자와 단기 트레이딩을 병행하자

주식은 묵혀두는게 아닙니다. 꾸준히 관심을 가지고 지켜봐야 합니다. 가능 하면 두가지 방법을 병행하면서 리스크를 줄여나는 것이 핵심입니다.

반응형

안드로이드 블루투스 관련 앱을 만들어보고 싶어, 해당 내용에 관한 글을 정리했습니다.

Bluetooth Low Energy (BLE)

기기간에 마스터, 슬레이브 관계를 형성하여 통신하는 bluetooth classic과 비슷한 무선 통신을 할 수 있었다. 그러나 전력량이 많았다. 기존의 문제이던 전력 소모량을 줄여, 스마트 기기인 스마트 밴드, 워치, 글래스 등에서 사용됩니다.
Classic Bluetooth의 경량화 버전을 목표로 bluetooth 4.0의 일부로 발표 되었습니다. 블루투스 표준화 그룹인 SIG에 의해서 개발되기 전까지 Nokia의 사내 프로젝트로 시작했습니다.

BLE 를 지원하는 기기는 Advertise mode (= broadcast ) 와 Connection mode로 통신을 합니다.

img

Advertise Mode (= Broadcast Mode )란?

주변의 디바이스 유무에 관계없이 자신의 signal을 일방적으로 계속 보내는 것을 말합니다. signal을 일방적으로 보내기 때문에 보안에 취약합니다. 디바이스에 자신의 존재를 알릴 때 사용하지만 observer에 전송할 작은양의 data를 보낼 때도 사용하기도 합니다.

Advertise 방식은 주로 디바이스가 자신의 존재를 알리거나, 적은 양(31Bytes 이하)의 User 데이터를 보낼 때도 사용됩니다. 한 번에 보내야 하는 데이터 크기가 작다면, 굳이 오버헤드가 큰 connection 과정을 거쳐 데이터를 보내기 보다, 단순히 advertise를 통해 한번에 보내는게 더 효율적이기 때문입니다. 전송크기 제한을 보완하기 위해 Scan Request, Scan Response을 이용해서 추가적인 데이터를 주고 받을 수 있습니다.

Advertise 방식은 signal을 일방적으로 뿌리는 것이기 때문에, 보안에 취약합니다.

일대 다 방식.

  • advertiser(boardcaster) : Non-Connectable Advertising Packet signal을 주기적으로 보내는 기기 ( ex. 스마트 워치, 밴드 등 )
  • observer : advertiser가 보내는 packet을 듣기 위해 주기적으로 scanning 하는 기기 ( ex. 폰 )
  • Advertising type 의 신호를 일정주기로 보냅니다.

Connection Mode란?

양방향으로 데이터를 주고 받거나, advertising으로만 데이터를 주고 받기에는 data 양이 많을 경우 Connection Mode로 통신합니다. 일대 일 방식으로 데이터를 교환한다. 디바이스간의 channel hopping 규칙을 정해놓고 통신을 하기 때문에 안전합니다.

Central ( Master )

다른 device와 connection을 맺기 위해 Connection advertise signal을 주기적으로 scan하고, 해당 디바이스에 연결 요청합니다.

연결 후에는 주기적으로 data 교환을 주도 합니다. ( ex. 폰 )

Peripheral ( Slave )

다른 device와 conneciton을 위해 advertise signal을 주기적으로 보낸다. 이를 수신한 Central 디바이스가 Connection request를 보내면 이를 수락하여 Connection 합니다. ( ex. 스마트 밴드 )

Protocol Stack

디바이스들이 bluetooth로 통신하기 위해 Protocol Stack을 가지고 있는데, 통신 규약인 protocol이 쌓여 있는 것을 Protocol Stack 이라 한다. Protocol Stack을 거치면서 packet 이 분석된다.

  • Application - App
  • Host - GAP ( Generic Access Profile ) , GATT(Generic Attribute Profile)
  • Controller - Link Layer, Physical Layer

Physical Layer

Bluetooth Signal과 통신할 수 있는 회로가 구성되어 있다. Analog 신호 <-> Digital 신호

2.4GHz 신호를 40개의 channel로 나누어 통신하는데 그 중 3개는 Advertising Channel, 나머지 37개는 Data Channel이다.

Link Layer

5가지의 state를 가지고 있다. 각 디바이스는 서로 연결되는 과정에서 State 를 변화 시킨다.

  • Standby : Signal packet을 보내지도, 받지도 않는 상태
  • Advertising : advertising packet을 보내고, 해당 advertising packet에 대한 상대 디바이스의 response를 받을 수 있고, 줄 수 있는 상태
  • Scanning : Advertising channel에서 scanning 하고 있는 상태
  • Initial : advertiser의 connectable advertising packet을 받은 후 Connection request를 보낸 상태
  • Connection : connection 이 후의 상태

Generic Access Profile ( GAP )

서로 다른 제조사가 만든 BLE끼리 호환할 수 있도록 하는 역할.
GAP은 서로 다른 제조사가 만든 BLE 디바이스들간에 서로 호환되어 통신할 수 있도록 주춧돌 역할을 한다. 어떻게 디바이스간에 서로를 인지하고, Data를 Advertising하고, Connection을 맺을지에 대한 프레임워크를 제공한다.

또한 GAP에서는 BLE 통신을 위해 Role, Mode, Procedure, Security, Additional GAP data format 등을 정의한다.

## Role

  • Central: Link layer에서 Master 역할에 상응. 다른 디바이스의 Advertising Packet을 듣고, Connection을 시작할 때 시작된다.
  • 메인 컴퓨터, 스마트폰, 태블릿PC의 역할
  • Peripheral: Link layer에서 Slave 역할에 상응. Advertising Packet을 보내서 Central 역할의 디바이스가 Connection을 시작할 수 있도록 유도.
  • 센서기능이 달린 디바이스들의 역할
  • Generic Attribute Profile ( GATT )

BLE data 교환을 관리. 디바이스들이 data를 발견하고, 읽고, 쓰는 것을 가능하게 하는 기초적인 data model과 procedure을 정의한다.

Connection mode일 때 GATT 서비스와 Characteristic을 이용하여 양방향 통신을 한다.

주요 용도에 대한

  • iBeacon prefix(9 byte) : 비콘의 설정이나 특성 값이 기록되는 부분입니다. iBeacon 헤더 정보라 생각하시면 됩니다. 우리가 손대지 않고 정해진 값을 사용해도 됩니다.
  • UUID (16 byte) : 사실 iBeacon에서 가장 중요한 데이터는 UUID, Major, Minor 값입니다. 이 값을 추출한 뒤, 서버에 보내서 내가 어느 위치에 있는지, 이 비콘이 어떤 역할을 하는지, 그래서 사용자에게 어떤 정보를 보여주는 것이 좋은지 판단하게 됩니다. iBeacon 관련 공식 문서를 보면 주변에서 스캔한 UUID, Major, Minor 로 사용자의 위치를 판단하는 예시들을 언급하는데, iBeacon 장치가 위치기반 서비스의 일부임을 표시하기 위해 미리 정해둔 UUID 를 사용합니다. UUID는 꼭 표준에 지정된 값을 쓸 필요는 없으며, 서비스 개발자가 임의로 지정해서 사용해도 됩니다.
  • Major (2 byte), Minor (2 byte) : UUID 와 함께 사용자의 위치(Major, Minor = 지역, 세부 장소)를 판별하는데 주로 사용됩니다. 하지만 사용방법이 고정된 것은 아니며, 개발자가 이 값들을 임의의 목적으로 사용할 수도 있습니다. 예를 들어, 온도와 습도 데이터를 Major, Minor 데이터로 보낼 수도 있습니다. 물론 이 경우 비콘을 스캔 하는 장치도 해당 데이터를 온도, 습도로 인식하도록 만들어야 합니다.
  • TX Power(1 byte) : 비콘 장치가 신호를 송출할 때의 power 레벨을 여기에 적어 보내줍니다. 비콘 신호를 수신할 때 신호 세기를 알 수 있기 때문에 TX power 보다 얼마나 감소했는지를 계산하고, 대강의 거리를 짐작할 수 있습니다. 하지만 이렇게 계산된 거리는 대략적인 추정치입니다. 비콘 신호는 주변 상황이나 움직임, 장애물에 의한 변동이 심할 수 있습니다.

References

  1. https://binux.tistory.com/26
반응형

소프트웨어에 개발에서 실수를 했을 때, 간단히 돌아오는 방법이 있습니다. GIT을 사용해서 프로젝트를 관리한다면 실수에서 벗어나는데 큰 도움이 됩니다.

1. 추적 된 파일 추적 금지

빈번히 발생하는 일 중에 node_modules를 포함해서 commit 했고, .gitignore파일이 없다는 것을 발견 했습니다. 이제서야 .gitignorenode_modules를 추가 했지만, git은 여전히 node_modules 을 추적하고 있습니다.
git base에 commit이 되면서 git이 계속변경 사항을 추적하기 때문입니다. 이를 중지하기 위해서는 아래와 같이 입력 합니다.

git base 에 있는 파일이 삭제 됩니다.

git rm -r --cached node_modules

2. 마지막 commit 수정

local -> git remote 로 commit을 했습니다. 그 후 커밋 파일에 변경 사항을 포함하는 것을 잊었습니다. 또는 가장 최근 커밋한 동일한 커밋에 연결하려는 새 파일을 추가합니다.

git은 이전 커밋을 잠금 해제하고 새 파일을 추가 할 수 있습니다.

git add newfile
git commit --amend -no-edit

--no-edit: commit 메세지를 변경하지 않고, comiit을 수정합니다.

3. 마지막 commit 메세지 수정

위의 수정내용과 비슷합니다. git에 commit을 했는데, commit 한 메세지가 원하는 내용과 달라졌습니다.

git commit --amend -m '메세지가 #2 로 바뀜'

4. 작업 폴더내의 작업내역 삭제

프로젝트를 진행하고 있습니다. 코드를 수정하는 동안 프로그램이 손상되었고, 실제로 무엇이 잘못 되었는지 파악할 수 없게 되었습니다.
현재 작업내용을 취소하고 마지막 commit 시점으로 돌아가야 할 것 같습니다.

git restore .

또는

git reset --hard

이 작업 local 저장소에서 최근 커밋으로 복원 합니다. 커밋하지 않는 내용은 모두 손실 됩니다.

5. 특정파일에 대한 작업 내용 취소

local 저장소의 파일을 수정했습니다. 히지만, test.js 파일의 변경 사항이 의미가 없었다는 것을 알고, 폐기하려고 합니다.

git restore test.js

6. 시간을 거슬러 이전 버전으로 파일 복원

위의 명령어와 달리 파일을 이전 특정 시점 상태로 돌아가기를 원합니다. test.js 파일을 최근 commit 된 내용이 v10 이지만, v2 시점으로 돌아가려고 합니다.

git log


commit d94629103526ddfa0715ca9393362a3b70e097b
Merge: aa034a93 1809aa89
Date:   Tue Aug 9 07:40:00 2022 +0900

    Merge pull request #15 from aaaaaday/master

commit 1809aklflkajlkhfeff890913ec751b36167560
Date:   Sun Aug 7 16:26:45 2022 +0100

    리뷰에 따라 수정 완료

commit 1b93eehwkhflwkehf280b513806b000dd033b9f
Date:   Sat Aug 6 00:58:16 2022 +0100

    원문과 최대한 라인수 일치하도록 수정

를 통해 복원하려고 하는 시점의 commit hash 를 찾습니다.

git restore --source <commit-hash> <파일이름>

7. 삭제한 파일 복원 (이전 commit)

프로젝트를 새로 변경하고 있는데 사용되지 않는 파일이 표시됩니다. 계속해서 파일을 삭제 했습니다.
그러나, 삭제한 파일 deleted_file.js가 필요하다는 것을 알게 되었습니다.

git restore deleted_file.js

8. local 저장소의 모든 변경사항을 remote 상태로 취소합니다.

local repo 브런치에세 몇가지 변경 사항과 commit을 했습니다. 그런데, 변경 사항을 모두 pull을 받았을 당시로 되돌리려고 합니다.

git reset --hard origin/master

commit 되지않는 파일은 영구적으로 삭제 됩니다.

9. 추적되지 않는 파일 삭제 (untracked file)

프로젝트에 여러 개의 새 파일을 만들고 일부 파일도 수정했습니다. 접근 방식을 변경했으며 이제 생성한 새 파일이 더 이상 필요하지 않지만, 수정된 파일 변경 사항을 유지하기로 결정했습니다.
Git은 추적되지 않은 파일을 제거하는 명령을 제공합니다.

git clean -f

git clean 명령에는 force 지시문(또한 --force)을 의미하는 -f 플래그가 필요합니다.

이 작업에는 추적되지 않은 파일 삭제가 됩니다. Git에서 커밋되지 않은 작업을 제거하는 것은 취소할 수 없습니다.

기본적으로 이 명령은 .gitignore로 지정된 추적되지 않은 폴더나 파일을 제거하지 않습니다. 무시된 파일을 제거하려면 -x 옵션을 지정하십시오. 또한 git clean은 디렉토리에서 재귀적으로 작동하지 않습니다.
이것은 우발적인 영구 삭제를 방지하기 위한 또 다른 안전 메커니즘입니다. 디렉토리를 제거하려면 다음과 같이 -d 플래그를 사용하십시오.

자식 청소 -df 이렇게 하면 추적되지 않은 파일과 디렉토리가 지워지지만 .gitignore 파일에 나열된 파일과 디렉토리는 제거되지 않습니다.

10. commit 을 다른 branch로 전환

프로젝트가 발전했으며 현재 newsletter 추가와 layout 미세 조정이라는 두 가지 기능을 작업하고 있습니다. newletterlayout이라는 두 개의 별도 분기를 만들었으며 각 분기를 관련 기능인 뉴스레터 및 레이아웃 전용으로 지정했습니다.

현재 뉴스레터 기능을 추가하고 있으며 뉴스레터 분기에서 몇 가지 커밋을 수행하고 있습니다. 다음에 프로젝트로 돌아올 때 레이아웃 기능에 대해 작업하려고 하는데 연결된 레이아웃 분기로 전환하는 것을 잊었습니다. 잘못된 뉴스레터 분기에서 레이아웃 기능을 추가하고 커밋했습니다.

나중에 뉴스레터 분기에 추가한 커밋이 실제로 레이아웃 분기에 속한다는 사실을 알게 됩니다.

따라서 커밋 추가 레이아웃 기능이 뉴스레터 분기에서 올바른 레이아웃 분기로 이동되기를 원합니다.

Git에서 수행할 작업은 다음과 같습니다.

newleter 지점으로 checkout

git checkout newletter

레이아웃 기능을 추가한 커밋의 커밋 해시를 찾아 복사합니다. 다음 명령을 실행합니다.

git log
# aceew89e0ac

이 커밋으로 적용하려는 올바른 브랜치를 확인하십시오. 우리의 경우:

git checkout layout

# 확인한 hash을 layout branch에 적용
git cherry-pick <commit-hash> 

그런 다음 뉴스레터 분기를 확인합니다.

git checkout newletter
# 잘못 commit 한 내용을 삭제 합니다.
git reset HEAD~1 --hard
or
git reset HEAD^ --hard

HEAD~1은 뉴스레터 브랜치를 재설정하여, 가장 최근 커밋 뒤로 하나의 커밋을 옮기고 다른 곳으로 이동한 커밋을 제거한다는 의미입니다. 우리의 경우 이 newletter 분기에 대한 최신 커밋은 layout 기능이 있는 커밋이었습니다.

11. 삭제된 branch 부활시키기

더 이상 기능 브랜치가 필요하지 않다고 생각하고 삭제했습니다. 다음번에는 삭제가 실수였다는 사실을 알 수 있습니다. 이 황당한 사건에 대해서 당황해 합니다. 당신은 불가능하게 시간을 되돌려 그것을 되찾고 싶어합니다.
삭제된 브랜치를 되돌리고 싶어합니다.

삭제된 브랜치를 복구하는 방법은 다음과 같습니다.

명령을 실행할 때 나열될 삭제된 분기의 커밋 해시를 찾아 복사합니다.

git reflog

그런 다음 다음과 같이 분기를 다시 만듭니다.

git branch <new-branch-name> <삭제된 브런치 hash>

이것은 <deleted-branch-commit-hash>까지의 모든 작업을 포함할 분기를 다시 생성합니다. <deleted-branch-commit-hash>가 삭제된 분기의 최신 작업이 아닌 경우, 최신 작업이 있는 커밋을 얻을 때까지 새 커밋 해시를 찾을 수 있습니다.
git branch를 입력하면 이전에 삭제한 브랜치가 다시 나열되는 것을 볼 수 있습니다. 이것은 Origin(remote)에서 브랜치가 삭제된 경우에도 작동합니다.

<branch-name>이 원하는 이름이 아닌 경우 git branch -m <branch-name> <new-branch-name>으로 이름을 바꾸면 됩니다.

삭제된 브랜치를 성공적으로 되돌리는 열쇠는 올바른 커밋 해시를 찾는 것입니다. 커밋의 이름을 똑똑하게적 지정하십시오. 그것은 많은 도움이됩니다.

12. 잘못된 commit 되돌리기

팀에서 새 버전의 프로젝트를 출시했습니다. 추가된 모든 새로운 기능이 절대적인 마스터 클래스임을 모두 확신합니다. 잠시 후 팀 리더의 긴급 전화로 새 버전에 중요한 결함이 있으며 즉시 수정해야 한다는 연락이 왔습니다. 엔지니어링 팀은 긴급 조치를 취해야 하며, 앉아서 결함을 찾는 것은 긴급한 문제에 대한 적절한 대응이 아닙니다.

가장 빠른 응답 중 하나는 오류가 발생하기 쉬운 릴리스에 대한 변경 사항을 취소하는 것입니다. 따라서 커밋에 대한 변경 사항을 취소하고 싶습니다.

Git에서 진행하는 방법은 다음과 같습니다.

변경 사항을 취소하려는 커밋(깨진 커밋)의 커밋 해시를 찾아 복사합니다.

git log
# 해당 커밋에 지정된 변경 사항 되돌리기
git revert <잘못 된 commit-hash>

git revert는 되돌린 변경 사항으로 새 커밋을 만듭니다.

깨진 커밋에 지정된 모든 변경 사항은 새 커밋에서 롤백됩니다. 예를 들어, 깨진 커밋에서 제거된 모든 것이 새 커밋에 추가되고, 깨진 커밋에서 추가된 모든 것이 새 커밋에서 제거됩니다.
생성될 커밋 되돌리기에 대한 기본 커밋 메시지와 함께 기본 편집기가 팝업됩니다. 원하는 대로 수정할 수 있습니다.

13. merge(병합) 취소

기능 분기의 새로운 변경 사항에 만족합니다. 기능 브랜치를 메인 브랜치에 병합할 준비가 된 것 같습니다. 따라서 기본 분기에서 기능 분기를 병합하고, 새 변경 사항을 원격 저장소에 푸시합니다.

잠시 후, 병합이 실제로는 그다지 좋은 코드가 아니라는 것을 알게 되었습니다. 그래서 병합을 취소하고 싶습니다.

# master branch로 이동합니다
git checkout master
# 병합 commit의 hash를 확인합니다
git log
# 되돌리기
git revert -m 1 <merge-commit-hash>

병합의 분기는 해당 병합의 부모입니다.

일반적으로 git은 병합의 어느 쪽(부모)이 메인라인으로 간주되어야 하는지 모르기 때문에 병합을 되돌릴 수 없습니다. git revert -m 1 메인라인의 상위 번호를 지정하고 지정된 상위 항목에 상대적인 변경 사항을 되돌리기 위해 revert를 허용합니다.

일반적으로 git merge 중에 가장 먼저 기록되는 부모는 병합할 때 있던 분기입니다. 여기서 오류의 경우 메인 브랜치에서 체크아웃하는 동안 feature 브랜치를 병합했습니다. 따라서 -m 1은 주 분기를 지정합니다.

14. 이전 버전으로 롤백

프로젝트를 이전 버전으로 롤백할 수 있습니다. 이렇게 하면 최근에 깨진 커밋 이전에 올바르게 작동하던 버전으로 돌아가려고 합니다.

여기에 표시된 git 명령은 기록을 다시 씁니다. 다른 사람과 소프트웨어 프로젝트를 공동 작업할 때는 적합하지 않습니다. 부득이 작업을 하게 된다면 다른 사람들에게 해당 내용을 공유하여야 합니다.

따라서 리포지토리의 기록을 되감아 프로젝트의 이전 버전으로 이동하려고 합니다.

git reset --hard <commit-hash>

git reset은 HEAD 포인터(따라서 작업 트리)를 이전 버전(<commit-hash>)으로 이동합니다.
이 버전 이후의 커밋은 프로젝트 기록에서 제거됩니다.

--hard 플래그는 스테이징 영역과 작업 트리를 재설정합니다.

git reset --mixed <commit-hash>와 같은 --mixed 플래그를 사용하면 저장소를 작업 트리의 지정된 커밋 해시 보존 파일로 다시 재설정합니다. 이후 커밋에 있었지만 재설정한 커밋에는 없는 파일은 추적되지 않는 파일이 됩니다.

--mixed 플래그는 인덱스(스테이징 영역)를 처리하는 방식에 차이가 있지만 --soft와 가까운 사촌이 있습니다.

--mixed 플래그는 스테이징 영역(색인)을 재설정하지만 작업 트리는 재설정하지 않습니다. 따라서 다음 커밋에서 추적되지 않은 파일을 추가하려면 git add 다음 git commit해야 합니다.

--soft 플래그는 스테이징 영역이나 작업 트리를 재설정하지 않습니다. 따라서 다음 커밋에서 추적되지 않은 파일을 추가하려면 git commit만 하면 됩니다.

15. 이전 커밋 메시지 수정

프로젝트 진행에 만족합니다. 프로젝트 기록을 살펴보고 있습니다. 하지만, 모호한 커밋 메시지를 발견했습니다. 따라서 이 메시지를 논리적 의미를 설명하는 더 나은 메시지(더 나은 설명이 있는 메시지)로 변경하려고 합니다.

Git에서 대화형(interactive) rebase를 사용하여 기록에서 더 깊은 커밋 메시지를 편집할 수 있습니다. 커밋 메시지를 변경하려는 커밋의 커밋 해시를 찾아 복사합니다.

rebase 대화형 세션을 엽니다.

git rebase -i <commit-hash>

편집기가 나타납니다.

위의 샘플 대화형 rebase 세션에서 1행에 오타가 있음을 알 수 있습니다. 이 오타를 수정하고 더 나은 설명 메시지를 제공하겠습니다.

편집기에서 수행하려는 작업만 지정합니다. 지금 당장 커밋 메시지를 다시 작성하고 싶을 수 있지만, 그렇게 하지는 않습니다. rebase -i는 SHA(커밋 해시) 열 이후의 모든 것을 무시합니다. 그 뒤의 텍스트는 커밋 해시가 무엇인지 기억하는 데 도움이 됩니다.

커밋의 내용을 유지하지만 커밋 메시지를 편집하려면 메시지를 변경하려는 커밋에 대해 reword action 명령을 지정하십시오. 다음과 같이 첫 번째 열의 단어 선택을 단어 reword(또는 r만)로 바꾸면 됩니다.

 (1 year, 7 months ago) Auto Deploy (Merge pull request #3 from node/translation/ch03 - github-actions[bot]
noop

# Rebase 53723b64..53723b64 onto 53723b64 (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#         create a merge commit using the original merge commit's
#         message (or the oneline, if no original merge commit was
#         specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
#                       to this position in the new commits. The <ref> is
#                       updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

Reword 리베이스 작업

그런 다음 편집기를 저장하고 닫습니다.

마지막으로 git은 커밋 메시지를 변경할 수 있는 편집기를 엽니다. 커밋 메시지를 더 나은 것으로 변경하십시오.

이전 커밋 메시지 업데이트

마지막으로 편집기를 저장하고 닫을 수 있습니다. 커밋은 새 커밋 메시지로 업데이트됩니다.

16. 오래된 커밋 삭제

오래된 커밋이 당신을 귀찮게 할 수 있으며 프로젝트 기록에서 삭제되기를 원할 수 있습니다. 따라서 이 커밋이 더 이상 프로젝트 기록에 나타나지 않기를 원합니다.

다음과 같이 이 커밋을 삭제할 수 있습니다.

먼저, 예정된 커밋의 커밋 해시를 찾아 복사합니다.

git log

git rebase -i <commit-hash>

커밋을 삭제하기 위한 drop 액션 단어를 지정합니다:

pick f39873d 안녕
pick c33dih3 방가워
drop 24dddvw 삭제하고 싶은 commit
pick dpojafe 하하하

편집기를 저장하고 닫습니다. 예정된 커밋은 프로젝트 기록에서 제거됩니다.

17. 이전 커밋에 새로운 변경사항 수정

프로젝트에 변경 사항을 추가하려는 상황이 발생할 수 있습니다. 그러나 이 변경 사항은 특정 변경 사항을 처리하던 당시의 커밋과 관련이 있습니다.

예를 들어, 프로젝트는 여러 커밋으로 발전했으며 아마도 가장 최근 커밋을 프로젝트의 v5로 브랜드화할 수 있습니다. file.js을 만들었습니다. 당신은 이 파일이 아마도 프로젝트 v2에서 더 깊은 기록의 이전 커밋의 일부가 되기를 원합니다.

Git에서는 새로운 변경 사항을 커밋에 다시 결합하여 이전 커밋을 편집할 수 있습니다.

단계는 다음과 같습니다.

편집용으로 표시하려는 커밋의 커밋 해시를 찾아 복사합니다.

git log

#rebase interactive
git rebase -i "<commit-hash>^"

<commit-hash> 끝에 캐럿(^)을 추가하는 방법에 유의하십시오. 이렇게 하면 이 표시된 커밋을 편집한 후 커밋의 원래 연대기로 돌아가고 싶다고 Git에 알릴 수 있습니다. git rebase -i "<commit-hash>^"를 실행하면 git log에 표시된 <commit-hash>가 가장 최근 커밋으로 표시되기 때문입니다.

이 명령을 실행하면 기본 편집기가 나타나고, <commit-hash>를 언급하는 줄에서 편집할 작업 동사 선택을 수정합니다.

작업 트리와 프로젝트 기록은 이제 이전에 커밋했을 때의 상태입니다. git log를 실행하면 <commit-hash>가 가장 최근 커밋임을 알 수 있습니다. 작업 트리에 생성한 파일(file.js)이 여전히 있으며 가장 최근 커밋으로 수정할 수 있는 좋은 기회입니다. 이 시점에서 가장 최근 커밋이 편집하려는 커밋임을 기억하십시오.

따라서 다음과 같이 수정하십시오.

git add file.js
git commit --amend --no-edit
# 기록을 정상순서로 되돌리기
git rebase --contirnue

이런 식으로 file.js을 추가하여 <commit-hash>에 지정된 커밋을 편집했습니다.

경고: 이렇게 하면 해당 시점부터 기록이 다시 작성됩니다. 팀 환경에서 프로젝트를 작업할 때는 좋은 생각이 아닙니다.

팀프로젝트에서는 기록을 다시 쓰는 것은 지양해야 합니다. 많은 소스 꼬임이 발생할 수 있습니다.

반응형

유용한 학습 사이트

텍스트

문자열

문자열의 자료형은 &'static str'이다.

  • &은 메모리 내의 장소를 참조하고 있다는 의마(mut가 없으므로 값의 변경을 허용하지 않음)
  • 'static'은 문자열 데이터가 프로그램이 끝날 때까지 유효하다는 의미이다 (절대로 Drop 되지 않는다)
  • str은 언제가 유효한 utf-8 바이트 열을 가리키고 있다는 의미
    fn main() {
      let a: &'static str = "hi";
      println!("{} {}", a, a.len());
    }

예외 처리 문자

어떤 문자들은 시각적으로 표현하기 어려우므로, 예외 처리 코드로 대체해서 쓴다.

  • \n: 줄바꿈
  • \r: 캐리지 리턴
  • \t: 탭
  • \\: 역슬래시
  • \O: NULL
  • \': 작은 따옴표
fn main() {
    let a: &'static str = "Ferris says:\t\"hello\"";
    println!("{}", a);
}

원시 문자열

원시 문자열은 r#"로 시작하고 "#로 끝나며 문자열을 있는 그대로 쓰는데 사용한다.

fn main() {
    let a: &'static str = r#"
        <div class="advice">
            Raw strings are useful ofr some situations.
        </div>
    "#;
    println!("{}", a);
}

파일에서 몬자열 가져오기

매우 큰 텍스트가 필요하다면 include_str! 매크ㄹㅗㄹㅡ 이용해 ㄹㅗ컬 파일에서 텍스트를 읽어오는 방식을 고려해보자

fn main() {
    let html = include_str!("test.html");
    println!("{}", html);
}

문자열 슬라이스

메모리 상의 바이트 열에 대한 참조이며, 언제나 유효한 UTF-8이어야 한다.
&str에서 자주 사요하는 메소드는 다음과 같다

  • len은 문자열 바이트 길이를 가겨온다. (글자수 아님)
  • start_withends_with는 기본적인 비교에 쓰인다
  • is_empty는 길이가 0일 경우 true를 리턴한다.
  • find는 주어진 텍스트가 처음 등장하는 위치인 Option<usize> 값을 리턴한다.
fn main() {
    let a = "hi.";
    println!("{}", a.len());
    let first_word = &a[0..2];
    let secord_word = &a[3..7];
    println!("{} {} ", first_word, secord_word);
}

문자

rust에서는 utf-8 바이트 열을 char 타일의 벡터로 돌려주는 기능을 제공하다.
char 하나는 4byte다.

fn main() {
    let chars = "hi there 😄".chars().collect::<Vec<char>>();
    println!("{}", chars.len());
    println!("{}", chars[9] as u32);
}

스트링

UTF-8 바이트 열을 힙 메모리에 소유하는 구조체
문자열과는 달리 변경하거나 기타 등들을 할 수 있다. (메모리가 힙에 있기 때문)
자주 사용하는 메소드는 다음과 같다.

  • push_str은 스트링의 맨 뒤에 UTF-8 바이트들을 더 붙일 때 사용한다.
  • replce는 utf-8 바이트 열을 다른 것으로 교체할 때 사용한다.
  • to_lowercaseto_uppercase는 대소문자를 비교할 때 사용한다.
  • tim은 공백을 제거할 때 사용한다.
fn main() {
    let mut helloworld = String::from("hello      ");
    helloworld.push_str("world ");
    helloworld = helloworld + "!";
    println!("{}", helloworld);
    let mut trim_to_right = helloworld.trim().to_string();
    trim_to_right = trim_to_right + "!";
    println!("{}", trim_to_right);
}

함수 매개변수로서의 텍스트

문자열과 스트링은 일반적으로 함수에 문자열 슬라이스 형태로 전달된다.
이 방법은 소유권을 넘길 필요가 없어 대부분의 경우에 유연한다.

fn say_it_loud(msg: &str) {
    println!("{}!!!!", msg.to_string().to_uppercase());
}
fn main() {
    say_it_loud("hello");
    say_it_loud(&String::from("goodbye"));
}

스트링 만들기

concatjoin은 스트링을 만드는 간단한지만 강력한 방법

fn main() {
    let helloworld = ["Hello", " ", "World", "!"].concat();
    let abc = ["a", "b", "c"].join("");
    println!("{}", helloworld);
    println!("{}", abc);
}

스트링 양식 만들기

format! 매크로는 값이 어디에 어떻게 놓일지 매개번수화된 스트링을 정의해 생성한다.
println!과 같이 매개변수화된 스트링을 사용한다

fn main() {
    let a: i32 = 42;
    let f: String = format!("secret to lite: {}", a);
    println!("{}", f);
}

##스트링 변환
to_string을 사용해 많은 데이터 바입을 스트링으로 변환할 수 있다.
제네릭 함수 parse로 스트링이나 문자열을 다른 데이터 타입을 갖는 값으로 변환할 수 있다. 이 함수는 실패할 수도 있기 때문에 Result를 리턴한다.

fn main() -> Result<(), std::num::ParseIntError> {
    let a = 42;
    let a_string = a.to_string();
    let b = a_string.parse::<i32>()?;
    println!("{} {}", a, b);
    Ok(())
}

객체 지향 프로그래밍(OOP)

OOP란 무엇인가

객체 지향프로그래밍은 다음과 같은 상징적 특징을 갖는 프로그래밍 언어를 뜻한다.

  • 캡슐화(Encapulation): 객체라 불리는 단일 타입의 개념적 단위에 데이터와 함수를 연결
  • 추상화(Abstraction): 데이터와 함수를 숨겨 객체의 상세 구현 사항을 알기 어렵게 함
  • 다형성(Polymorphism): 다른 기능적 관점에서 객체와 상호 작용하는 능력
  • 상속(Inheritance): 다른 객체로부터 데이터와 동작을 상속받는 능력

RUST는 OOP가 아니다

Rust에서는 어떠한 방법으로도 데이터와 동작의 상속이 불가능하다.

  • 구조체는 부모 구조체로부터 필드를 상속받을 수 없다.
  • 구조체는 부모 구조체로부터 함수를 상속받을 수 없다.

메소드 갭슐화하기

Rust는 메소드가 연결된 구조체인 객체라는 개념을 지원한다.
모든 메소드의 처번째 매개변수는 메소드 호출과 연관된 인스턴스에 대한 참조여야한다.

  • &self: 인스턴스에 대한 변경 불가능한 참조
  • &mut self: 인스턴스에 대한 변경 가능한 참조
    메소드는 impl 키워드를 쓰는 구현 블록 안에 정의 한다.
struct SeaCreature {
    noise: String,
}

impl SeaCreature {
    fn get_sound(&self) -> &str {
        &self.noise
    }
    fn set_sound(&mut self, new_noise: &str) {
        self.noise = new_noise.to_string();
    }
}
fn main() {
    let creature = SeaCreature {
        noise: String::from("blub"),
    };
    println!("{}", creature.get_sound());
}

선택적 노출을 통한 추상화

Rust는 객체의 내부 동작을 숨길 수 있다
기본적으로, 필드와 메소드들은 그들이 속한 모듈에서만 접근 가능하다.
pub 키워드는 구조체의 필드와 메소드를 모듈 밖으로 노출시킨다.

struct SeaCreature {
    pub name: String,
    noise: String,
}

impl SeaCreature {
    pub fn get_sound(&self) -> &str {
        &self.noise
    }
    fn set_sound(&mut self, new_noise: &str) {
        self.noise = new_noise.to_string();
    }
}
fn main() {
    let creature = SeaCreature {
        name: String::from("Ferris"),
        noise: String::from("blub"),
    };
    println!("{}", creature.get_sound());
}

다형성과 트레잇

  • Rust는 트레잇으로 다형성을 지원한다. 트레잇은 메소드의 집합을 구조체 데이터 타입에 연결할 수 있게 해준다.
  • 먼저 트레잇 안에 메소드 원형을 정은한다. 구조체가 트레잇을 구현할 때, 실제 데이터 타입이 무엇인지 알지 못하더라도 트레잇 데이터 타입을 통해 간접적으로 구조체와 상호 작용할 수 있도록 협약을 맺게 된다.
  • 구조체의 구현된 트레잇 메소드들은 구현 블록 안에 정의된다.
struct SeaCreature {
    pub name: String,
    noise: String,
}

impl SeaCreature {
    pub fn get_sound(&self) -> &str {
        &self.noise
    }
}

trait NoiseMaker {
    fn make_noise(&self);
}

impl NoiseMaker for SeaCreature {
    fn make_noise(&self) {
        println!("{}", &self.get_sound())
    }
}

fn main() {
    let creature = SeaCreature {
        name: String::from("Ferris"),
        noise: String::from("blub"),
    };
    creature.make_noise();
}

트레잇에 구현된 메소드

  • 트레잇에 메소드를 구현해 넣을 수 있다
  • 함수가 구조체 내부의 필드에 직접 접근할 수는 없지만, 트레잇 구현체들 사이에서 동작을 공유할 때 유용하게 쓰인다.
    struct SeaCreature {
      pub name: String,
      noise: String,
    }
    

impl SeaCreature {
pub fn get_sound(&self) -> &str {
&self.noise
}
}

trait NoiseMaker {
fn make_noise(&self);
fn make_alot_of_noise(&self) {
self.make_noise();
self.make_noise();
self.make_noise();
}
}

impl NoiseMaker for SeaCreature {
fn make_noise(&self) {
println!("{}", &self.get_sound())
}
}

fn main() {
let creature = SeaCreature {
name: String::from("Ferris"),
noise: String::from("blub"),
};
creature.make_alot_of_noise();
}


## 동적 vs 정적 디스패치

- 메소드는 다음의 두 가지 방식으로 실행된다.
    - 정잭 디스패치(Static Dispatch): 인스턴스의 데이터 트입을 알고 있는 경우, 어떤 함수를 호출해예 하는지 정확히 알고 있다.
    - 동적 디스패치(Dynamic Dispatch): 인스턴스의 데이터 타입을 모르는 경우, 올바른 함수를 호촐할 방법을 찾아야 한다.
- 트레잇의 자료형인 `&dyn MyTrait`은 동적 디스패치를 통해 객체의 인스턴스들을 간접적으로 작동시킬 수 있게 해준다.
- Rust에서는 동적 디스패치를 사용할 경우 사람들이 알 수 있도록 트레잇 자료형 앞에 `dyn`을 붙일 것을 권고한다.

```rust
struct SeaCreature {
    pub name: String,
    noise: String,
}

impl SeaCreature {
    pub fn get_sound(&self) -> &str {
        &self.noise
    }
}

trait NoiseMaker {
    fn make_noise(&self);
}

impl NoiseMaker for SeaCreature {
    fn make_noise(&self) {
        println!("{}", &self.get_sound())
    }
}
fn static_make_noise(creature: &SeaCreature) {
    creature.make_noise();
}
fn dynamic_make_noise(noise_maker: &dyn NoiseMaker) {
    noise_maker.make_noise();
}

fn main() {
    let creature = SeaCreature {
        name: String::from("Ferris"),
        noise: String::from("blub"),
    };
    static_make_noise(&creature);
    dynamic_make_noise(&creature);
}

트레잇 객체

  • 객체의 인스턴스를 &dyn MyTrait 데이터 타입을 가진 매개 변수로 넘길 때, 이를 트레잇 객체라고 한다.
  • 트레잇 객체는 인스턴스의 올바른 메소드를 간접적으로 호출할 수 있게 해주며, 인스턴스에 대한 포인터와 인스턴스 메소드들에 대한 함소 포인터 목록을 갖는 구조체이다

크기를 알 수 없는 데이터 다루기

  • 트레잇은 원본 구조체를 알기 어렵게 하느라 원래 크기 또한 알기 어렵다.
  • Rust에서 크기를 알 수 없는 값이 구조체에 저장될 때는 두 가지 방법으로 처리된다.
    • generics: 매개 변수의 데이터 타입을 효과적으로 활용해 알려진 데이터 타입 및 크기의 구조체/함수를 생성한다
    • indirection: 인스턴스를 힙에 올림으로써 실제 데이터 타입의 크기 걱정이 없이 그 포인터만 저장할 수 있는 간접적인 방법을 제공한다.

제네릭 함수

  • Rust의 제네릭은 트레잇과 함께 작동한다. 개매 변수 데이터 타입 T를 정의할 때 해당 인자가 어떤 트레잇을 구현해야 하는지 나열함으로써 인자에 어떤 데이터 타입을 쓸 수 있는지 제한할 수 있다.
  • 제네릭을 이용하면 컴파일 시 데이터 타입과 크기를 알 수 있는 정적 데이터 타입이 함수가 만들어지며, 따라서 정적 디스패치와 함께 크기가 정해진 값으로 저장할 수 있게 된다.
struct SeaCreature {
    pub name: String,
    noise: String,
}

impl SeaCreature {
    pub fn get_sound(&self) -> &str {
        &self.noise
    }
}

trait NoiseMaker {
    fn make_noise(&self);
}

impl NoiseMaker for SeaCreature {
    fn make_noise(&self) {
        println!("{}", &self.get_sound())
    }
}
fn generic_make_noise<T>(creature: &T)
where
    T: NoiseMaker,
{
    creature.make_noise();
}

fn main() {
    let creature = SeaCreature {
        name: String::from("Ferris"),
        noise: String::from("blub"),
    };
    generic_make_noise(&creature);
}

제네릭 함수줄여쓰기

fn generic_make_noise<T>(creature: &T)
where
    T: NoiseMaker,
{
    creature.make_noise();
}

// 아래와 같이 변경 가능

fn generic_make_noise(creature: &impl NoiseMaker) {
    creature.make_noise();
}

스마트 포인터

BOX

  • BOX는 스택에 있는 데이터를 힙으로 옮길 수 있게 해주는 자료 구조다.
  • 스마트 포인터로도 알려진 구조체이며 힙에 있는 데이터를 가리키는 포인터를 들고 있다.
  • 크기가 알려져 있는 구조체이므로(왜냐하면 포인터만 들고 있으므로) 필드의 크기를 알아야하는 구조체에 뭔가의 참조를 저장할 때 종종 사용된다.
struct SeaCreature {
    pub name: String,
    noise: String,
}

impl SeaCreature {
    pub fn get_sound(&self) -> &str {
        &self.noise
    }
}

trait NoiseMaker {
    fn make_noise(&self);
}

impl NoiseMaker for SeaCreature {
    fn make_noise(&self) {
        println!("{}", &self.get_sound())
    }
}

struct Ocean {
    animals: Vec<Box<dyn NoiseMaker>>,
}

fn main() {
    let ferris = SeaCreature {
        name: String::from("Ferris"),
        noise: String::from("blub"),
    };
    let sarah = SeaCreature {
        name: String::from("Sarah"),
        noise: String::from("swish"),
    };
    let ocean = Ocean {
        animals: vec![Box::new(ferris), Box::new(sarah)],
    };
    for a in ocean.animals.iter() {
        a.make_noise();
    }
}

참조 다시보기

  • 참조는 근본적으로 메모리 상의 어떤 바이트들의 시작 위치를 가리키는 숫자일 뿐이며, 유일한 용도는 특정 타입의 데이터가 어디에 존재하는지에 대한 개념을 나타내는 것이다.
  • 일반 숫자와 차이점은 Rust에서 참조가 가리키는 값보다 더 오래 살지 않도록 수명을 검증한다는 거다. ( 안그러면 그걸 사용핼을 때 오류가 날 것이다)

원시 포인터

  • 참조는 더 원시적인 자료형인 원시 포인터로 변환될 수 있다
  • 원시 포인터는 숫자와 마찬가지고 거의 제한없이 여기저기 복사하고 이동할 수 있다.
  • Rust는 원시 포인터가 가리키는 메모리 위치의 유효성을 보증하지 않는다.
  • 원시 포인터에는 두 종류가 있다
    • *const T: 데이터 타입 T의 데이터를 가리키는 절대 변경되지 않는 원시 포인터
    • *mut T: 데이터 타입 T의 데이터를 가리키는 변경될 수 있는 원시 포인터
  • 원시 포인터는 숫자와 상호 변환이 가능하다. (예: uszie)
  • 원시 포인터는 안전하지 않은 코드의 데이터에 접근할 수 있다
fn main() {
    let a = 42;
    let memory_location = &a as *const i32 as usize;
    println!("memory location: {}", memory_location);
}![[Javascript _ Null 과 undefined]]

역참조

  • 참조(예: &i32) 를 통해 참조되는 데이터를 접근/변경하는 과정을 역참조라고 한다.
  • 참조로 데이터를 접근/변경하는 데에는 두 가지 방법이 있다.
    • 변수 할당 중에 참조되는 데이터에 접근
    • 참조되는 데이터의 필드나 메소드에 접근
  • Rust에는 이를 가능케 하는 강력한 연산자가 있다.

* 연산자

  • * 연산자는 참조를 역참조하는 명시적인 방법이다.
fn main() {
    let a: i32 = 42;
    let ref_ref_ref_a: &&&i32 = &&&a;
    let ref_a: &i32 = **ref_ref_ref_a;
    let b: i32 = *ref_a;
    println!("{}", b);
}
  • .연산자는 참조의 필드와 메소드에 접근하는 데에 쓰인다. (좀 더 미묘하게 동작하는데, 참조 열을 자동으로 역참조한다.)
struct Foo {
    value: i32,
}

fn main() {
    let f = Foo { value: 42 };
    let ref_ref_ref_f = &&&f;
    println!("{}", ref_ref_ref_f.value);
    // -> println!("{}", (***ref_ref_ref_f).value);
}

스마트 포인터

  • Rust에서는 & 연산자로 이미 존재하는 데이터의 참조를 생성하는 기능과 대불어, 스마트 포인터라 불리는 참조 같은 구조체를 생성하는 기능을 제공한다.
  • 고수준에서 보자면 참조는 다른 데이터 타입에 대한 접근을 제공하는 데이터 타입이라고 볼 수 있다. 스마타 포인터가 일반적인 참조와 다른 점은, 프로그래머가 작성하는 내부 로직에 기반해 동작하는 거다.
  • 일반적으로 스마트 포인터는 구조체가 *.연산자로 연참조될 때 무슨 일이 발생할 지 지정하기 위해 Deref, DerefMut, Drop 트레잇을 구현한다.
use std::ops::Deref;

struct TattleTell<T> {
    value: T,
}

impl<T> Deref for TattleTell<T> {
    type Target = T;

    fn deref(&self) -> &T {
        println!("{} was used!", std::any::type_name::<T>());
        &self.value
    }
}

fn main() {
    let foo = TattleTell {
        value: "secret message",
    };
    println!("{}", foo.len());
}
// &str was used!
// 14

위험한 스마트 코드

  • 스마트 포인터는 안전하지 않는 코드를 꽤 자주 쓰는 경향이 있다. 앞서 말했듯이, 스마트 포인터는 rust에서 가장 저수준의 메모리를 다루기 위한 일반적인 도구다.

  • 무엇이 안전하지 않은 코드일까? 안전하지 않는 코드는 rust 컴파일러가 보증할 수 없는 몇가지 기능이 있다는 예외사항을 제외하고는 일반적인 코드와 완전히 똑같이 동작한다.

  • 안전하지 않는 코드의 주 기능은 원시 포인터를 역참조하는 것이다. 이는 원시 포인터를 메모리 상의 위치에 가져다 놓고, “데이터 구조가 여기 있다!”고 선언한 뒤 사용할 수 있는 데이터 표현으로 변환하는 걸 의미한다. (즉, *const u8u8로)

  • Rust에서는 메모리에 쓰여지는 모든 바이트의 의미를 추적하는 방법이 없다. 원시 포인터로 쓰이는 임의의 숫자에 무엇이 존재하는지 보증할 수 없기 때문에, 역참조를 unsafe { ... } 블록 안에 넣는다.

    fn main() {
      let a: [u8; 4] = [86, 14, 63, 12];
      let pointer_a = &a as *const u8 as usize;
      println!("Data memory location: {}", pointer_a);
    
      let pointer_b = pointer_a as *const f32;
      let b = unsafe { *pointer_b };
      println!("I swear this is a pie! {}", b);
    }
    

// Data memory location: 140701859722372
// I swear this is a pie! 0.00000000000000000000000000000014718419


## 익숙한 친구들

- 이미 본 적이 있는 `Vec<T>`나 `String` 같은 스마트 포인터를 생각해 보자.
- `Vec<t>` 는 바이트들의 메모리 영역을 소유하는 스마트 포인터다. Rust 컴파일러는 이 바이트들에 뭐가 존재하는지 모른다. 스마트 포인터는 관리하는 메모리 영역에서 내용물을 꺼내기 위해 자기가 뭘 의미하는지 해석하고, 데이터 구조가 그 바이트들 내 어디에서 시작하고 끝나는지 추척하며, 마지막으로 원시 포인터를 데이터 구조로, 또 쓰기 편한 깔금한 인터페이스로 역참조한다. (예: `my_vec[3]`)
- `String`는 바이트들의 메모리 영역을 추적하며, 쓰여지는 내용물이 언제나 유효한 UTF-8이도록 프로그램적으로 제한하며, 그 메모리 영역을 `&str` 데이터 타입으로 역참조할 수 있도록 도와준다.
- 두 데이터 구조 모두 원시 포인터에 대한 안전하지 않은 역참조를 사용한다.
- 
```rust
use std::alloc::{alloc, Layout};
use std::ops::Deref;

struct Pie {
    secret_recipe: usize,
}

impl Pie {
    fn new() -> Self {
        let layout = Layout::from_size_align(4, 1).unwrap();
        unsafe {
            let ptr = alloc(layout) as *mut u8;

            ptr.write(86);
            ptr.add(1).write(14);
            ptr.add(2).write(15);
            ptr.add(3).write(92);
            Pie {
                secret_recipe: ptr as usize,
            }
        }
    }
}
impl Deref for Pie {
    type Target = f32;
    fn deref(&self) -> &f32 {
        let pointer = self.secret_recipe as *const f32;
        unsafe { &*pointer }
    }
}

fn main() {
    let p = Pie::new();
    println!("{:?}", *p);
}
// result:
// 1.6106674e17

힙에 할당 된 메모리 Box::

Box는 데이터를 스택에서 힙으로 옮길 수 있게 해주는 스마트 포인터다. 이를 역참조하면 마치 원래 데이터 타입이었던 것처럼 힙에 할당 된 데이터를 편하게 쓸 수 있다.

struct Pie;

impl Pie {
    fn eat(&self) {
        println!("tastes better on the heap!");
    }
}
fn main() {
    let heap_pie = Box::new(Pie);
    heap_pie.eat();
}
// result : tastes better on the heap!

참조 카운팅 Rc::

  • Rc는 스택에 있는 데이터를 힙으로 옮겨주는 스마트 포인터다. 이는 heap에 놓인 데이터를 변경 불가능하게 대여하는 기능을 갖는 다른 Rc 스마트 포인터를 복제할 수 있게 해준다.
  • 마지막 스마트 포인터가 Drop될 때에만 힙에 있는 데이터가 할당 해제된다.
use std::rc::Rc;

struct Pie;

impl Pie {
    fn eat(&self) {
        println!("tastes better on the heap!");
    }
}
fn main() {
    let heap_pie = Rc::new(Pie);
    let heap_pie2 = heap_pie.clone();
    let heap_pie3 = heap_pie2.clone();

    heap_pie3.eat();
    heap_pie2.eat();
    heap_pie.eat();
    println!(
        "heap_pie3 = {:p}, heap_pie2 = {:p}, heap_pie = {:p}",
        heap_pie3, heap_pie2, heap_pie
    );
}
// result
// tastes better on the heap!
// tastes better on the heap!
// tastes better on the heap!
// heap_pie3 = 0x7fa007f05c80, heap_pie2 = 0x7fa007f05c80, heap_pie = 0x7fa007f05c80

접근 공유하기 RefCell::

  • RefCell은 보통 스마트 포인터가 보유하는 컨테이너 구조로서, 데이터를 가져오거나 안에 있는 것에 대한 변경 가능한 또는 불가능한 참조를 대여할 수 있게 해준다.
  • 데이터를 대여할 때, Rust는 런타임에 메모리 안전 규칙을 적용해 남용을 방지한다.
    “단 하나의 변경 가능한 참조 또는 여러 개의 변경 불가능한 참조만 허용하며, 둘 다는 안됨”
    이 규칙을 어기면 RefCell은 패닉을 일으킨다.
use std::cell::RefCell;

struct Pie {
    slices: u8,
}

impl Pie {
    fn eat(&mut self) {
        println!("tastes better on the heap!");
        self.slices -= 1;
    }
}
fn main() {
    let pie_cell = RefCell::new(Pie { slices: 8 });
    {
        let mut mut_ref_pie = pie_cell.borrow_mut();
        mut_ref_pie.eat();
        mut_ref_pie.eat();
    }

    let ref_pie = pie_cell.borrow();
    println!("{} slices left", ref_pie.slices);
}
// result:
// tastes better on the heap!
// tastes better on the heap!
// 6 slices left

스레드 간에 공유하기 Mutex::

  • Mutex는 보통 스마트 포인터가 보유하는 컨테이너 데이터 구조로서, 데이터를 가져오거나 안에 있는 것에 대한 변경 가능한 또는 불가능한 참조를 대여할 수 있게 해준다.
  • 잠긴 대여를 통해 운영체제가 동시에 오직 하나의 CPU만 데이터에 접근 가능하도록 하고, 원래 스레드가 끝날 때까지 다른 스레드들은 막음으로써 대여남용을 방지한다.
  • Mutex는 여러 개의 CPU 스레드가 같은 데이터에 접근하는 걸 조율하는 방법이다.
  • 특별한 스마트 포인터인 Arc도 있는데, 스레드-안전성을 가진 참조 카운타 증가 방식을 사용한다는 걸 제외하고는 Rc와 동일하다.
    • 동일한 Mutex에 다수의 참조를 가질 때 종종 사용되곤 한다.
use std::sync::Mutex;

struct Pie;
impl Pie {
    fn eat(&self) {
        println!("tastes better on the heap!");
    }
}
fn main() {
    let mutex_pie = Mutex::new(Pie);

    let ref_pie = mutex_pie.lock().unwrap();
    ref_pie.eat();
}
// result
// tastes better on the heap!

스마트 포인터 조합하기

스마트 포인터는 한계가 있는 것처럼 보이지만, 조합해서 사용하면 매우 강력해질 수 있다.

  • Rc<Vec<Foo>> : 힙에 있는 변경 불가능한 데이터 구조의 동일한 벡터를 대여할 수 있는 복수의 스마트 포인터를 복제할 수 있게 해준다.
  • Rc<RefCell<Foo>>: 복수의 스마트 포인터가 동일한 Foo구조체를 변경 가능하게 또는 불가능하게 대여할 수 있게 해 준다.
  • Arc<Mutex<Foo>>: 복수의 스마트 포인터가 임시의 변경 가능한 또는 불가능한 대여를 CPU 스레드 독점 방식으로 잠글 수 있게 해준다.
use std::{cell::RefCell, rc::Rc};

struct Pie {
    slices: u8,
}
impl Pie {
    fn eat_slice(&mut self, name: &str) {
        println!("{} ate a slice of pie!", name);
        self.slices -= 1;
    }
}
struct SeaCreature {
    name: String,
    pie: Rc<RefCell<Pie>>,
}
impl SeaCreature {
    fn eat(&self) {
        let mut p = self.pie_borrow_mut();
        p.eat_slice(&self.name);
    }
    fn pie_borrow_mut(&self) -> std::cell::RefMut<Pie> {
        self.pie.borrow_mut()
    }
}
fn main() {
    let pie = Rc::new(RefCell::new(Pie { slices: 8 }));
    let ferris = SeaCreature {
        name: String::from("ferris"),
        pie: pie.clone(),
    };
    let sarah = SeaCreature {
        name: String::from("sarah"),
        pie: pie.clone(),
    };
    ferris.eat();
    sarah.eat();

    let p = pie.borrow();
    println!("{} slices left", p.slices)
}
// result
// ferris ate a slice of pie!
// sarah ate a slice of pie!
// 6 slices left/

프로젝트 구성과 구조

프로그램/라이브러리 작성하기

  • 프로그램은 main.rs 라 불리는 파일에 최상위 모듈을 갖고 있다.
  • 라이브러리는 lib.rs라 불리는 최상위 모듈을 갖고 있다.

다른 모듈과 crate 참조하기

  • 모듈 내의 항목은 전체 모듈 경로인 std::f64::consts::PI를 이용해 참조할 수 있다.
  • 더 간단한 방법은 use 키워드를 사용하는 거다. ㅣㅇ를 이용하면 모듈에서 쓰고자 하는 특정 항목을 전체 경로를 쓰지 않고도 코드 어디에서든 사용할 수 있다.
    • 예를 들어, use std::f64::consts:PI를 쓰면 main 함수에서 PI만으로 사용할수 있다
  • std는 유용한 데이터 구조 및 OS와 상호 작용할 수 있는 함수로 가득한 표준 라이브러리(Standard Library)의 crate다.

여러 개의 항목은 참조하기

복수의 항목을 하나의 모듈 경로로 참조하고 싶다면 다음과 같이 사용하면 된다.

use std::f64::consts::{PI, TAU}

모듈 작성하기

코드를 생각할 때 보통은 디렉토리로 구성된 파일 구조를 떠올린다.
Rust에서는 모듈을 선언하는 두가지 방법이 있다.

  1. foo.rs 라는 파일이름
  2. foo라는 이름의 디렉토레이 들어있는 파일 mod.rs

모듈 계층구조

한 모듈은 다른 모듈에 의존할 수 있다. 모듈과 하위 모듈 사이에 관계를 지어주려면, 부모 모듈에 코드 mod foo;를 작성하면 된다.
foo.rs 파일이나 foo/mod.rs 파일을 찾아 범위 내의 foo 모듈 안에 그 내용물을 삽입한다.

인라인 모듈

  • 하위 모듈은 모듈의 코드 내에 직접 치환 될 수 있다.
  • 인라인 모듈의 가장 흔한 용도는 유닛 테스트를 만들 때다. Rust가 테스트에 쓰일 때에만 존재하는 인라인 모듈을 만들 수 있다.
#[cfg(test)]
mod tests {
    use super::*;
    // test code
}

내부 모듈 참조하기

rust에서는 use경로에 사용할 수 있는 몇가지 키워드를 통해 원하는 모듈을 빠르게 가져다 쓸 수 있다.

  • create : 최상위 모듈
  • super: 현재 모듈의 부모 모듈
  • self: 현재 모듈

내보내기

기본적으로 모듈의 구성원들은 외부에서 접근이 불가능하다. (자식 모듈에게까지도!) pub 키워드를 사용하면 모듈의 구성원들을 접근 가능하게 할 수 있다.
기본적으로 crate의 구성원들도 외부에서 접근이 불가능하다. 크레이트의 최상위 모듈에 pub를 표시하면 구성원들을 접근 가능하게 할 수 있다.

구조체 가시성

구조체도 함수와 마찬가지로 pub를 사용해 모듈 외부로 무엇을 노출할 지 선엉할 수 있다

pub struct SeaCreature {
    pub animal_type: String,
    pub name: String,
    pub arms: i32,
    pub legs: i32,
    weapon: String,
}

Prelude 모듈

use로 가져오지 않았는데, 어떻게 Vec, Box를 사용할 수 있을까? 이는 표준 라이브러리의 prelude 모듈 덕분이다.
Rust의 표준 라이브러리에서는 std::prelude::**로 내보내기 된 모든 것들이 어디에서든 자동으로 사용 가능하다. Vec, Box가 바로 이런 경우이며, 다른 것들 (Opton, Copy 등 )도 마찮가지다.

반응형

'개발 > rust' 카테고리의 다른 글

RUST 학습 1주차  (0) 2022.10.17
RUST 소개  (0) 2022.10.09
rust 유용한 명령어  (0) 2022.10.07

+ Recent posts