728x90
반응형

Java 개발자를 위한 Rust, 소개

시작할 준비를 하세요...

Rust에 대해 들어보셨고 Java 개발자이신가요? Rust를 사용해 보고 싶나요? 이 글은 당신이 기초부터 시작할 수 있도록 노력할 것입니다. Java와 Rust의 기본적인 차이점과 몇 가지 함정에 빠지는 것을 피하고 빌림 검사기와 너무 많이 싸우는 것을 피하려고 합니다. 그 의도는 당신이 Java에서 온 Rust 개발자의 사고방식에 들어가는 데 도움이 되기를 바라는 것입니다.

툴체인 등을 설치하는 방법은 여기서 다루지 않을 것입니다. 그 부분은 충분히 다루었습니다. 그들의 웹사이트에 있는 가이드 는 어쨌든 당신이 필요로 하는 전부일 것입니다.

그럼 본격적으로 Java 프로그램이 Rust 프로그램과 어떻게 다른지 살펴보겠습니다. 보다 더 좋은 예가 Hello, World!있습니까? 이 소개에서 이 예제를 기반으로 시작하여 몇 가지 토대를 마련할 몇 가지 주제를 다룰 것입니다.

첫 번째 프로그램 실행

Java라고 하면 몇 가지를 의미합니다. 물론 언어 자체; JDK 클래스; JDK 도구; 그리고 자바 가상 머신. Hello, World!컴퓨터 화면 에 인쇄하는 데 필요한 모든 것입니다 . HelloWorld.java프로그램 소스 는 다음과 같습니다 .

class HelloWorld {
    public static void main(String... args) {
        System.out.println("Hello, World!");
    }
}

우리가 선언하는 곳에서 class, named HelloWorld. 자체적으로 단일 정적 메서드를 선언하며, 많은 C 스타일 언어와 마찬가지로 일반적으로 main. String마지막으로 해당 메서드는 호출 시 런타임에 의해 채워질 프로그램에 전달된 인수를 나타내는 인스턴스 배열을 허용합니다 .

메서드의 본문은 모든 Java 개발자에게 매우 간단합니다 out. 클래스의 정적 필드를 조회하고 해당 객체 System에서 메서드 .println()를 호출하여 string 을 전달합니다 Hello, World!.

이것을 실행해 봅시다. 여기서는 Java 19를 사용하고 있으므로 java JVM(Java Virtual Machine)에 먼저 컴파일하지 않고 소스 파일을 전달하기만 하면 됩니다.

$ java --version
openjdk 19.0.1 2022-10-18
OpenJDK Runtime Environment (build 19.0.1+10-21)
OpenJDK 64-Bit Server VM (build 19.0.1+10-21, mixed mode, sharing)

$ java HelloWorld.java
Hello, World!

모든 것이 매우 간단하며 실제로 마법이 없습니다. 아니면… 있나요? Rust에서 같은 결과를 얻는 것이 어떻게 약간 다른지 봅시다. 먼저 Rust에서 동등한 프로그램을 작성해야 합니다. 다음은 우리의 작은 것입니다 hello.rs.

fn main() {
    println!("Hello, World!"); 
}

main소스는 상당히 비슷하지만 우리 메서드 에 외부 클래스나 다른 장식이 없다는 것을 알아차렸을 것입니다 . 이 경우에는 함수 이므로 방법이 아닙니다 . 정적 메서드는 함수 자체에 가깝다고 주장할 수 있습니다. main여기서는 확실히 Java의 정적 메서드와 같이 클래스 인스턴스나 클래스에 연결되지 않은 함수 입니다. Rust의 함수는 Java에서와 같이 " funfn " 으로 발음되는 키워드 접두사가 붙은 이름을 사용하여 선언됩니다 . Rust의 함수가 유형이 지정된 인수 목록을 선언할 것으로 예상할 수 있지만 Java에서와 마찬가지로 프로그램의 진입점 역할을 하는 함수는 인수를 취하지 않습니다. 잠시 후에 다시 다루겠습니다.main

마지막으로 Java에서와 마찬가지로 중괄호 안에 있는 함수의 본문은 크게 다르지 않습니다. 함수와 같은 매크로를 호출합니다 . Rust에서 이러한 매크로는 !쉽게 인식할 수 있도록 접미사 가 붙습니다. 어떻게 해결되는지 궁금하실텐데요. 명시적으로 를 참조한 Java와 달리 System.out.println()이 매크로의 출처를 나타내는 항목이 표시되지 않습니다. 매크로의 정의는 에서 찾을 수 있습니다 . 예를 들어 를 찾을 수 있지만 Java 프로그램에서 명시적으로 가져올 필요가 없는 와 어느 정도 동일 std::println!하다고 생각 하면 컴파일러가 이러한 문제를 해결하고 둘 다 그렇게 하는 방법 과 방법에 따라 다르지만 해당 주제는 다른 시간에 유지하겠습니다. 말하자면stdjava.langStringjavacrustcrustc하지만 Rust 컴파일러로 예제를 컴파일해 봅시다. 여기서는 도구 모음 버전 1.66을 사용합니다. 마지막으로 작은 프로그램을 실행합니다.

$ rustc --version
rustc 1.66.0 (69f9c33d7 2022-12-12)

$ rustc hello.rs

$ ./hello
Hello, World!

성공! Java를 사용할 때와 달리 프로그램을 실행하는 데 가상 머신이 필요하지 않기 때문에 명시적인 컴파일 단계를 거쳐야 했습니다. Java 예제를 네이티브 코드로 미리 컴파일할 수 있습니다. 이 경우 결과 바이너리는 Java Runtime을 실행하지 않아도 되지만 이 게시물에서는 Java 바이트 코드 기반 실행을 사용하여 몇 가지 차이점을 설명합니다. 두 언어로.

이제 우리는 Rust에서 기본 프로그램을 실행하는 방법을 살펴보았으므로 좀 더 흥미롭게 만들고 우리가 맞이하고 싶은 사람에 대해 좀 더 구체적으로 알아보겠습니다.

조금 더 정확히 알아보자

우리는 전 세계에 일반적으로 인사하는 것보다 특정 사람에게 인사함으로써 우리의 작은 예를 좀 더 흥미롭게 만들 수 있습니다. 몇 단계로 이 작업을 수행해 보겠습니다. 먼저 현재 상태에서 인사를 받는 사람을 포함하는 변수를 추출합니다 World. 인수가 제공되지 않는 경우 기본 주제로 계속 사용할 것입니다. Rust에서 이 작업을 수행하는 데는 그다지 관련이 없습니다:

let who = "World";
println!("Hello, {who}!");

보시다시피, 이것은 정말 간단합니다. 키워드 let를 사용하여 바인딩, 변수를 선언합니다 who. 두 번째 줄에서 방금 선언한 바인딩을 println! 해결하고 로 대체합니다 .{who}World

이제 남은 것은 who프로그램에 전달된 인수로 값을 재정의하는 것입니다(실제로 제공된 경우). 다시 말하지만 정말 간단해 보입니다. 대부분의 사람들이 이 글을 읽으면서 아래 Java 코드(또는 약간의 변형)를 상상할 수 있을 것이라고 확신합니다.

public class Greeter {
    
    public static void main(String... args) {

        var who = "World";
        if (args.length > 0) {
            who = args[0];
        }
        
        System.out.println("Hello, " + who + "!");
    }    
}

그러나 Rust 프로그램에서 동일한 작업을 수행하는 몇 가지 문제가 있습니다. 첫째, 논쟁의 출처는 어디입니까? 앞에서 언급했듯이 우리 main함수는 인수를 취하지 않습니다. 표준 라이브러리는 여기서 우리에게 std::env::args(). 이 함수는 개별 인스턴스 Args로 인수에 대한 반복자인 를 반환합니다.String

또 다른 문제는 Rust에서 변수 바인딩이 기본적으로 불변이라는 것입니다.  who, Java에서와 같이 프로그램에 전달된 이름을 재할당할 수 없습니다. 아니면 적어도 있는 그대로는 아닙니다. 한 가지 옵션은 바인딩을 가변으로 선언하는 것입니다. 이는 mut바인딩 선언에 키워드를 추가하여 수행됩니다.

let mut who = "World";

그러나 관용적인 Rust에서는 그렇게 하지 않을 것입니다. 이런 식으로 하지 않는 것이 실제로 좋은 이유가 있습니다. 위의 줄에서 실제로 말하는 것은 "무엇이든" who이 가리키는 것은 프로그램에 의해 변경 가능하다는 것입니다. 그러나 우리가 원하는 것은 제공된 경우에 대비하여 완전히 다른 다른 인스턴스에 바인딩하는 것입니다. 조건부 바인딩을 달성하는 몇 가지 방법이 who있습니다. if let다음 예에서 패턴을 선택했습니다 . 여기에는 몇 가지 이유가 있습니다. 그러나 지금은 Java에서 알고 있는 삼항 연산자 표현으로 생각하십시오 <booleanExpression> ? <expression1> : <expression2>(Rust에는 실제로 없는 연산자). var whoJava 버전에서 사용하면 위의 예에서 할당을 다음과 같이 리팩터링했을 것입니다 .

var who = args.length > 0 ? args[0] : "World" ;

다음은 greeter.rs예제의 모습입니다.

   

프로그램 의 첫 번째 줄 은 Java에서 패키지를 가져오는 것과 동일한 모듈use 의 를 선언합니다 . 모듈은 두 개의 콜론( )을 사용하여 구분하지만 Java는 점( )을 사용합니다. 이미 알고 있는 것과 크게 다르지 않습니다.std::env ::.

5  에서 이전 과 마찬가지로 키워드로 arguments바인딩을 선언합니다 . 그러나 이번에는 변수 이름 뒤에 콜론과 유형 정의가 옵니다. 이것이 Rust에서 특정 유형의 변수를 선언하는 방법입니다. 이 경우 컴파일러가 어떤 반복자 가 수집되어야 하는지 유추할 수 없기 때문에 유형 으로 선언 해야 합니다. 는 벡터이며 Java와 동일합니다 . 즉, 힙 할당 연속 성장 가능 배열 유형입니다. Java와 마찬가지로 Rust의 제네릭을 사용하여 벡터의 항목 유형을 선언합니다 . 러스트letwhoargumentsVec<String>StringVecArrayListVecStringStringJava에서와 같이 UTF-16이 아닌 UTF-8로 인코딩되며 변경될 수 있습니다. 마지막으로 를 채우는 방법에서 추론할 수 있듯이 Rust의 반복자는 해당 유형 Vec<String>보다 Java Streams에 더 가깝습니다 .Iterator

이제 프로그램에 전달된 모든 인수를 편리하게 사용할 수 있으므로 "World" 대신 인쇄할 항목이 실제로 제공되었는지 확인해야 합니다. 우리  우리.get(index)  Vec<String>. 그러나 그렇게 하기 전에 바인딩 검사를 수행하지 않는다는 사실에 아마 놀랄 것입니다! 인덱스가 범위 null를 벗어난 경우 반환될 것으로 예상할 수 있지만 . 그러나 Rust는 그런 일을 할 수 없었습니다. 왜냐하면 Rust에는 . 예, 당신은 그 권리를 들었습니다. null 값은 없습니다! 대신, 우리는 등을 얻습니다 . 개념적 으로 Java와 동일합니다. 그러나 Java 버전과 달리 이nullArrayList<String>nullOption<&String>Option<T>Optional<T>Option<T>적절한 Algebraic Data Type (ADT)이며 Rust는 이에 대한 일급 지원을 제공하지만 다른 게시물을 위한 것입니다. Rust에서 와 같이 선언 enum되었지만 Java에서 알고 있는 것과는 다릅니다. 그들이 상태를 가지고 있기 때문에. Option::Some(T)그러나 지금은 및 변형 이 있다는 것을 알아야 합니다 Option::None. 여기서 전자는 type 인스턴스의 존재를 나타내고 T후자는 인스턴스가 없음을 나타냅니다. 그것이 우리의 바인딩 anybody_at_all이 나타내는 것입니다. 인사할 사람이 있거나 아무도 없습니다. Rust는 카멜 케이스 대신 스네이크 케이스를 사용합니다( anybodyAtAll).

.nth(1)에서 요소를 조회한다는 것을 눈치채셨을 것입니다 Vec. 이는 Rust 인덱스가 1부터 시작하기 때문  아닙니다 . Rust는 Java와 마찬가지로 0부터 시작하는 인덱싱을 사용합니다. 그러나 벡터의 첫 번째(ie .nth(0)) 요소는 시작 시 호출된 실제 바이너리 이름이므로 아마도 ./greeter작업 디렉토리에 바이너리가 포함되어 있을 것입니다.

그리고 마지막 &으로 . Rust의 앰퍼샌드는 참조 를 정의합니다 . null이 없기 때문에 우리는 a가 어딘가 를 가리킨다는 것을 압니다. a , 즉 실제 String 값을 포함하는 벡터를 생성한 5 행 에서 수행한 것과는 달리 여기서는 해당 벡터 에 대한 참조  반환합니다 . 해당 문자열의 복사가 발생하지 않으며 남아 있는 소유권은 . Rust 는 실제로 String에 대한 참조인 Java와 동일합니다.StringOption<&String>&StringStringVec<String>.getOptionStringStringarguments&StringString

9행 은 표현식 을 사용하여 의 조건부 할당이 who발생하는 곳입니다. if let이 다소 이상한 코드 라인에서 다시 몇 가지 일이 진행되고 있습니다. 그래서 그것을 조금 분해합시다. 먼저 if let Some(one) = anybody_at_all 표현식 anybody_at_all은 a 인지 여부를 테스트합니다 Option::Some(T). 그렇다면 첫 번째 분기가 평가되고 그렇지 않으면 분기가 평가됩니다 else. 전자의 경우 if let문은 또한 Rust에서 디스트럭처링(destructuring)이라고 알려진 것을 수행합니다. 같음의 왼쪽은 일치할 것으로 예상되는 형식을 나타냅니다. one에서 값을 바인딩할 변수를 선언 합니다 Option::Some. if let그런 다음 해당 변수는 분기 범위 내에서 사용할 수 있게 됩니다 .

10번째 줄 도 아마 다소 놀랍거나 적어도 12번째 줄 만큼이나 놀랍습니다 . 둘 다 끝에 세미콜론( ;)이 없습니다. Rust에서는 거의 모든 것이 표현식입니다. 그러한 표현식이 무엇을 평가하는지 정의하기 위해 세미콜론이 없을 때 블록의 마지막 문이 표현식이 평가하는 값이 됩니다. 따라서 이 두 줄이 수행하는 작업은 반환 one(인수 목록에서 읽은 문자열 값에 대한 참조, 에 저장됨 arguments) 또는 표현식 "World"에서 반환하는 것입니다. 그런 다음 해당 값은 9행 의 표현식 앞에 선언한 if let바인딩과 연결됩니다 . 반면 13행 에는 뒤에 세미콜론이 있습니다. 의 끝을 표시합니다whoif letwho 변수 에 할당하는 let 문 . "작은" 리팩토링의 시작 부분에서 했던 것처럼 마침내 15행 에서 ​​인사할 준비가 되었습니다 …

$ rustc greeter.rs

$ ./greeter
Hello, World!

반면에 이제 우리 프로그램에 인수를 제공한다면… 드럼롤!

$ ./greeter John
Hello, John!

효과가있다! 글쎄요, 쉬웠죠?

let if표현이 다소 이상 하다면 사용할 수 있는 다른 솔루션이 있습니다. Rust에서도 매우 흔한 것 중 하나인 match문입니다. using match은 Java의 표현식에 가깝고 switch이전 예제와 마찬가지로 패턴 일치 및 구조 분해를 사용합니다. 다음과 같이 표시됩니다.

let who = match anybody_at_all {
    Some(one) => one,
    None => "World",
};

match식은 실제로 식일 뿐이므로 다시 할당하는 데 사용 합니다 who. let if식 tho 와 달리 식은 모든 변형 match에 대해 철저해야 합니다 .  Option가 2개 뿐이므로 큰 차이가 없으므로 다시 2개의 분기로 끝납니다. 하지만 이번에는 블록을 선언할 필요가 없습니다. 우리는 각각 의 분기가 표현식 2를 평가하는 값이 되도록 합니다.Option::Some(T)Option::Nonematch

우리 식과 실제로 동등한 것을 작성하려면 다음 과 같이 에 대해 명시적으로 일치하는 대신 밑줄을 let if사용하여 catch all을 our 의 마지막 분기로 사용할 수 있습니다 .matchNone_ ⇒ "World"

문자열은 의 "단지" 인스턴스입니다 String. 맞습니까?

우리는 위의 예에서 두 가지 중요한 개념 , 즉 선행 앰퍼샌드 문자 String로 표시되는 유형 및 참조를 소개했습니다. &위의 예에서 서로 다른 문자열에 어떤 일이 일어나는지 좀 더 자세히 살펴보겠습니다. 우리는 Rust 컴파일러가 우리를 위해 많은 유형을 추론할 수 있고 유형을 명시적으로 선언해야 하는 부담을 제거할 수 있음을 보았습니다. 우리는 여전히 이러한 유형을 명시적으로 선언할 수 있으며 이는 코드를 읽는 프로그래머에게 도움이 될 수 있으며 여기에는 우리 자신도 포함됩니다. 여기 이 예가 그러한 경우일 수 있으므로 다음과 같이 진행합니다.

   

가능한 경우 명시적 유형을 포함할 뿐만 아니라 인수가 제공되지 않았을 때 환영하는 everyone기본값인 새 변수도 있도록 코드가 약간 변경되었습니다. 4행 에서 "World"볼 수 있듯이 는 no 이지만 대신 어떤 유형입니다!? 앰퍼샌드는 지금까지 친숙할 것입니다. 참조입니다. 그러나 ? a가 무엇인지 설명하기 전에 먼저 프로그램을 컴파일할 때 어떤 일이 발생하는지 이해하겠습니다 . (참고용이니 기억하시죠?) 값 은 참으로 특별합니다. 프로그램에 제공된 인수와 달리"World"String&strstrstr"World"everyone"World"소스 코드에 바로 있기 때문에 컴파일 시간에 알 수 있습니다. 실제 값은 컴파일되는 결과 바이너리(이 경우 실행 파일) 내에 존재합니다. 프로그램이 메모리에 로드되면 "World". 그리고 everyone메모리의 해당 위치를 가리켜야 합니다. 그것은 참조를 설명하지만 str대신 String!

. _ everyone_ String우선 String 인스턴스는 Rust에서 변경 가능합니다. 이 문자열은 변경하면 안 됩니다. 즉, rustc는 이미 해당 참조를 변경 가능하게 만드는 것을 금지 &mut str합니다. 또한 a String는 항상 할당된 힙입니다. 실제로 Vec는 UTF-8 인코딩 문자열을 구성하는 바이트를 포함하는 에 의해 지원됩니다. 반면 an str은 유효한 UTF-8 바이트 시퀀스로의 슬라이스, 보기입니다. 때로는 문자열 슬라이스 라고도 합니다 . str당신은 실제로 직접 사용하지 않습니다 . 그러나 오히려 참조를 통해. An 은 컴파일 타임에 크기를 알 수 없는 str것으로도 알려져 있습니다 . !Sized참조는 해당 정보를 추가하고 실제 문자열의 길이 정보를 포함하는 것입니다.

그래서 우리 는 바이트 가 존재 everyone: &str하는 메모리의 어떤 위치를 가리키고 있습니다. World이것들은 바로 다른 문자열 값이나 쓰레기가 뒤따를 수 있습니다. 그것이 우리의 실제 str. 참조는 해당 위치와 그것이 가리키는 문자열의 길이를 인코딩합니다. 이 특별한 경우에는 5가 됩니다. 반면에 String인스턴스는 힙 할당되고 벡터를 포함하며, 벡터는 연속된 메모리 위치, 용량 및 현재 길이에 대한 포인터입니다. env::args()이것이 함수 호출 에 의해 프로그램의 인수가 사용 가능한 방식 입니다.

그런 다음 이러한 주장을 살펴보겠습니다. 현재 우리는 그것들을 모두 수집하여 6행arguments: Vec<String> 에 넣습니다 . 나중에 인쇄할 값에 대한 참조만 사용할 것이기 때문에 이렇게 합니다. 가치 자체가 아닙니다. 여기에 Rust와 Java의 또 다른 중요한 차이점이 있습니다. 가비지 수집기가 없습니다. 단점은 이제 유효한 항목에 대한 참조점이 필요하다는 것 입니다. 그리고 그 무언가는 더 이상 필요하지 않을 때 결국 해제되어야 합니다. 하지만 우리 코드를 보면 가비지 수집 언어가 아닌 다른 언어에서 알 수 있는 유사한 것이 없습니다 .freedelete

Rust는 C++ 개발자에게 잘 알려진 관용구를 사용합니다: Resource Acquisition Is Initialization 을 나타내는 RAII . 컴파일러는 객체가 범위를 벗어날 때 해제되는지 확인합니다(또는 Rust가 호출하는 대로 -ped). 위의 예에서 이는 함수가 끝날 때 우리를 생성하여 할당된 메모리 도 해제되고 누출되지 않음을 의미합니다. 그리고 인수가 제공되었을 때 사용자에게 메시지를 인쇄할 때 코드에서 해당 벡터에 대한 참조를 사용하므로 이것이 필요합니다. Rust 컴파일러는 모든 참조가 유효한 것을 가리키는 경우에만 프로그램이 컴파일되도록 합니다. 예를 들어 다음 과 같이 변수 를 인라인하여 몇 줄의 코드를 저장하려고 했습니다 .Dropmainlet arguments: Vec<String>arguments

let anybody_at_all = env::args().collect::<Vec<String>>().get(1);

코드가 컴파일되지 않습니다. 그것의 문제는 the가 아마도 (the )를 가리키는 인수의 값 Vec<String>을 소유 하는 the 가 생성되자마자 해제되어 참조가 유효하지 않을 수 있는 것을 가리킬 수 있다는 것입니다. 컴파일은 문제뿐만 아니라 수정 사항도 설명하는 멋진 오류 메시지를 제공합니다.anybody_at_all&String

$ 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
  |
help: consider using a `let` binding to create a longer lived value
  |
6 ~     let binding = env::args().collect::<Vec<String>>();
7 ~     let anybody_at_all: Option<&String> = binding.get(1);

이제 첫 번째 인수만 사용하므로 모든 인수를 메모리에 유지할 필요가 없습니다. 다음은 이를 수행하는 몇 가지 코드입니다. 먼저 첫 .skip(n)번째 항목을 -ping하고 다음 항목만 유지합니다. Option<String>다시 말하지만, 없을 수도 있으므로 를 반환합니다 . 이것이 첫 번째 줄입니다.

let anybody_at_all: Option<String> = env::args().skip(1).next();
let who = anybody_at_all.as_ref().map_or("World", String::as_str);

두 번째 줄에서 우리는 약간의 춤을 춥니다. 먼저 우리는 를 호출 .as_ref()합니다. 그러면 , 즉 에 대한 가능한 참조를 Option<String>반환 합니다 . 마지막 호출 은 두 가지 중 하나를 수행합니다. 값이 없는 경우 첫 번째 인수를 반환합니다. 즉, 유형이 있거나 값이 있는 경우 실제 값에 대한 메서드를 호출하여 매핑합니다 , 문자열에 a를 반환 합니다.Option<&String>String.map_or()"World"&str.as_str()&str

이제 이전 버전에서 명시적으로 one: &String" 매핑"할 필요가 없는 이유가 궁금할 것 입니다.&str

let who: &str = if let Some(one) = anybody_at_all {
    one
} else {
    everyone
};

 10행 이 읽히지 one.to_str()않습니까? 컴파일러는 실제로 우리를 위해 변환을 처리합니다. .to_str()그래도 using이 아니라 Java .deref()에서 인터페이스에 가장 가까운 특성인 특성에서 오는 using, std::ops::Deref. 따라서 10행  one.deref()암시적으로 됩니다. 이 메커니즘을 Deref강제 라고 합니다 . use명시적으로 직접 수행하려면 파일 맨 위에 해당 특성에 대한 설명 을 추가해야 합니다.

또는 명시적 표기법을 사용하여 를 사용하여 &String 를 로 String, 저것으로 역 str참조한 다음 를 사용하여 해당 참조를 반환합니다 &**one. 그것은 꽤 이상한 구문입니다. clippyRust linter는 실제로 다음을 사용하지 못하게 할 것입니다.

warning: deref which would be done by auto-deref
  --> greeter.rs:10:9
   |
10 |         &**one
   |         ^^^^^^ help: try this: `one`
   |

clippy위의 내용은 프로젝트 에 사용해야 하는 많은 이유 중 하나 입니다. 그것은 관용적 코드를 작성하는 Rust 방식에 익숙해지는 데 최소한 도움이 될 것입니다.

요약하자면

fn키워드 를 사용하여 Rust에서 함수를 선언하는 방법을 살펴보았습니다 . 함수는 Java의 정적 메서드와 동일하지만 클래스에 바인딩되지 않습니다. let키워드 를 사용하여 변수를 선언 했습니다. 대부분의 경우 컴파일러에서 유형을 유추할 수 있지만 변수 이름 :뒤에 콜론과 유형을 접미사로 추가하여 해당 유형 정보를 명시적으로 제공할 수 있습니다.

std::Option우리는 Rust 에서 enum우리가 Java에서 알고 있는 것과 다르다는 것을 보았습니다. 우리는 let if및 match문을 사용하여 몇 가지 방법으로 이들에 대해 패턴 일치를 수행했으며 조건부로 변수에 할당하기 위해 노출되는 보다 기능적인 스타일 API를 활용했습니다.

마지막으로 프로그램에 제공된 첫 번째 인수를 수집할 때 데이터가 있는 위치와 수명 주기에 대해 조금 더 생각했습니다. 두 가지 다른 유형의 문자열을 소개 했습니다. 참조 및 역 참조로 재생되었습니다 String.str

이 모든 것을 통해 여러분이 직접 Rust 실험을 시작할 수 있기를 바랍니다. 작은 프로젝트를 부트스트래핑하여 오늘 시작하는 것이 어떻습니까?

$ cargo new playground
     Created binary (application) `playground` package

$ cd playground

$ find *
Cargo.toml
src
src/main.rs

$ cat src/main.rs
fn main() {
    println!("Hello, world!");
}

$ cargo run
   Compiling testing v0.1.0
    Finished dev [unoptimized + debuginfo] target(s) in 0.78s
     Running `target/debug/playground`
Hello, world!

여기를 보세요, Hello, world!… 원점으로 돌아가세요! 그러나 그것은 당신을 시작할 것입니다. 빌드 도구 cargo는 도구 체인, Java의 maven 또는 gradle 등가물 및 Cargo.toml프로젝트의 매니페스트의 일부입니다.

시작하는 경우 cargo clippy코드 기반에서 정기적으로 실행하십시오. 다른 clippy와는 달리, 이 클립이 유용할 것이라고 약속합니다! 재미있을 것 같은 프레젠테이션 도 했습니다. 피드백이나 질문이 있으시면 알려주세요. 귀하에게 불분명한 사항이 있다면 다른 사람에게도 해당될 수 있습니다! 그리고 더 많은 것을 원하신다면 이 시리즈의 다음 게시물인 소유권, 차용 검사기 및 몇 가지 더 많은 내용을 계속 진행하세요!

 

 

 

https://wcgw.dev/posts/2023/rusty-java-intro/

728x90
728x90
반응형

당신이 진정으로 원하는 목표를 달성하기 위해


행동에 착수하는 순간,


두려움은 녹아 없어지기 시작한다.

 

 

로버트 앨런

 

728x90

'명언들모음' 카테고리의 다른 글

[명언] Jeff Atwood  (0) 2023.01.31
[명언]마야 안젤루 (Maya Angelou)  (1) 2023.01.01
728x90
반응형

Golang에서 사용하는 Standard Library 들이다. 갯수가 많지가 않아 초기 학습 곡선이 크게 높지는 않다. 하지만 하위 정보들이 별도로 있기 때문에 위에 나열한것만 있는건 아니다. 그렇지만 기본적으로 세팅된 1레벨 키워드로 봐서는 크게 많은게 아니니 학습하는데 너무 부담가지지 말자.

 

모든 언어들이 그렇지만 쉽게 배울 수 있다고 얘기하는 정보에 속지 말아야 한다. 어떤 언어든 깊숙히 들어가게 되면 거의 비슷한 난이도를 가진다. Javascript도 VBScript도 Python 도 초기 진입장벽이 낮다는거지 언어의 깊은부분까지 쉽다고 얘기하는건 아니다.

728x90
728x90
반응형

요즘 인공지능 이미지 생성기 Midjourney 나 chatGPT 같은 AI 서비스 프로그램들이 핫하다.

아무래도 앞으로는 이 관심도나 기술의 발전이 기하급수적으로 올라갈 것 같다.

 

어떤 문화나 트랜드의 확산형태는 늘 비슷했다. 

 

문제점이 도출된다.

사용자의 니즈가 간간히 나온다.

기술의 발전을 위한 기술에 사람들 관심이 쏟아진다.

자극적인 기사들이 나오면서 필요성을 어필한다.

많은 사람들이 뛰어든다.

그리고 많은 기술들이 실패한다.

회의적인 기사가 나타난다.

시간이 흐르면 다시 기술에 대한 언급이 시작된다.

위의 과정이 다시 반복된다.

기술적인 임계점이나 사회의 니즈에 대한 임계점에 다다르면 폭발한다.

기술의 발전속도와 니즈, 관심, 투자가 폭발적으로 발생한다.

단기간 혹은 장기간동안 트렌드가 된다.

 

인생을 살면서 관찰을 하기 시작한지 꽤 오래되었다. 

이 과정이 늘 반복된다.

AI 기술이 본격적으로 관심을 받고 탄력을 받게되면 다음 언어들이 관심을 가지게 될것 이다.

Golang, Rust, WebAssembly, Python, Dart 

그중에 가장 쉽다고 마케팅이 되어서 각인된 Python은 학습하려는 수요가 꽤 많이 폭발할 것 같다.

나머지 언어들은 프로그래머가 되겠다고 하는 사람들에게 더 관심이 많아서 수요가 Python 만큼 발생하지는 않겠지만 언어의 난이도 학습곡선 활용도 등등을 고려하면 앞으로 점점 더 사용자층이 두터워질 언어가 아닐까 조심스레 예측해본다.

 

오래전부터 관심을 가지고 간간히 공부해 오고 있던 언어이긴한데 프로그래머인 나에게는 그렇게 쉽지는 않은것 같다. 문법의 상이함이 자꾸 걸림돌이되고 사고의 확장을 방해한다. 

아뭏튼 꾸준히 공부하다보면 극복이 되겠지만 가끔씩 탁탁 걸리는 부분이 있어서 좀 괴롭긴하다.

 

이미 문법은 3번 학습을 했고 심화과정으로 넘어가야 하는데 몇가지 걸리는게 있어서 자꾸 늦어진다. 

GUI는 너무 느리고, UX는 구리고, 그냥 서버단으로만 사용하는게 맞는건지 애매모호한 포지션의 언어이다. (나에게는...)

일단 수요가 확인이 되었으니 학습을 더 본격적으로 시작해봐야겠다.

 

화이팅

728x90
728x90
반응형

앞으로 Svelte 를 학습해서 활용할 부분

Golang 기반의 Wails + Svelte + tailwind

Rust 기반의 Tauri + Svelte 

개발 언어들이 너무 짧은 주기에 좋은것들이 계속 나오니 정신을 못차리겠다.

학습을 해야 하는데 언어자체의 장점보다는 시장성을 빼놓을 수 없어서 Svelte를 배워둔다면 언제 써먹을지도 모를일이다.

Flutter도 이제 치고 들어오는데 React나 Svelte를 제껴두고 넘어가야되나 고민도 된다.

 

일단 한가지를 잡고 끝까지 완주해야 할텐데 어는걸 잡아서 하는게 맞을까?

정말... 시장성이 있는 React를 해야 하는건가? 아 골아프네.

728x90

'Temp' 카테고리의 다른 글

정말 짜증나는 Fasoo DRM !!  (0) 2023.01.19
728x90
반응형

앞으로 Svelte 를 학습해서 활용할 부분

Golang 기반의 Wails + Svelte + tailwind

Rust 기반의 Tauri + Svelte 

개발 언어들이 너무 짧은 주기에 좋은것들이 계속 나오니 정신을 못차리겠다.

학습을 해야 하는데 언어자체의 장점보다는 시장성을 빼놓을 수 없어서 Svelte를 배워둔다면 언제 써먹을지도 모를일이다.

Flutter도 이제 치고 들어오는데 React나 Svelte를 제껴두고 넘어가야되나 고민도 된다.

 

일단 한가지를 잡고 끝까지 완주해야 할텐데 어는걸 잡아서 하는게 맞을까?

정말... 시장성이 있는 React를 해야 하는건가? 아 골아프네.

728x90
728x90
반응형

SvelteKit 1.0 이 출시된 지 불과 2주가 지났습니다! 아직 하지 않았다면 라이브스트림, 새 웹사이트 및 learn.svelte.dev를 확인하여 SvelteKit  모든 기능  단계별로 알아보세요.

자세히 알아 보시죠.

SvelteKit의 새로운 기능

  • @sveltejs/kit1.0이 나왔습니다! 모든 향후 릴리스는 semver를 따르며 변경 사항은 CHANGELOG 에 주/부/패치로 나열됩니다 .
  • Storybook 및 Histoire에 대한 지원이 향상되었습니다( #7990 ). 이러한 도구를 완벽하게 지원하기 위한 작업이 진행 중입니다( storybook#20239 ).
  • vitePreprocess이제 기본 전처리기입니다.  ( #8036 ) 의 차이점 은 문서 를 참조하세요 .vitePreprocesssvelte-preprocess

브레이킹 체인지:

  • +(layout|page)(.server)?.js및 +server.js파일 에서 알 수 없는 내보내기(밑줄로 시작하는 경우 제외)가 더 이상 허용되지 않습니다 ( #7878 ) .
  • __data.json이제 URL에서 제거되었습니다( #7979 ) .
  • sveltekit()이제 Vite 플러그인 배열에 대한 약속을 반환합니다( #7994 ) .
  • embedded기본적으로 꺼져 있는 새 옵션은 SvelteKit을 포함할 때 링크 클릭에 도움이 됩니다( docs , #7969 ) .
  • builder.generateFallback(fallback)자동 폴백 생성이 ( #8013 ) 으로 대체되었습니다 .
  • invalid()지금 fail()이고 ValidationError지금입니다 ActionFailure( #8012 )
  • 이제 SvelteKit에서 잘못된 로드 응답에 대한 오류가 발생합니다( #8003 ) .
  • SvelteKit은 현재 Vite 4를 사용하고 있으며 Svelte가 필요합니다 peerDependency( ^3.54.0# 7543 ) .
  • ssr가 거짓이고 거짓 이 아닐 때 셸이 사전 렌더링 됩니다. prerenderssr도 거짓인 경우 사전 렌더링이 거짓인지 확인합니다( #8131 ) .
  • 제거/변경된 API에 대한 경고 및 오류가 제거되었습니다( #8019 ) .

Svelte의 새로운 기능

  • 이제 options.direction인수를 사용자 지정 전환 함수에 전달할 수 있습니다( 3.54.0 , #3918 ) .
  • @const이제 선언된 함수 에서 변수를 업데이트할 수 있습니다 ( 3.54.0 , #7843 ) .
  • svelte/elementsSvelte /HTML 유형 정의에 추가되었습니다( 3.55.0 , #7649 ) .

언어 도구의 새로운 기능

Svelte 확장 및 언어 도구에는 이제 몇 가지 새로운 최소 버전 요구 사항이 있습니다.

  • 노드 버전은 현재 16입니다.
  • TypeScript 버전은 이제 4.9입니다.
  • Svelte 버전은 이제 3.55입니다.

다음 기능도 릴리스되었습니다.

  • 누락된 처리기 빠른 수정( #1731 )
  • Svelte 앵커 누락 속성 코드 작업 추가( #1730 )
  • 더 나은 커밋 문자 처리( #1742 )
  • 옵션 추가 --preserveWatchOutput( #1715 )
  • Svelte Stores를 포함하도록 Quickfix 향상( #1789 )
  • SvelteKit 프로젝트에서 SvelteKit 파일 컨텍스트 메뉴만 표시( #1771 )
  • satisfies가능한 경우 연산자를 사용하십시오 ( #1770 ) .

출시되지 않은 변경 사항을 포함하여 Svelte 컴파일러에 대한 모든 변경 사항은 CHANGELOG 를 확인하십시오 .


커뮤니티 쇼케이스

Svelte로 구축된 앱 및 사이트

  • Svelte Recipes 🧑‍🍳 는 일반적인 데이터 시각화 문제에 대한 코드 스니펫을 제공합니다.
  • Everything Svelte 는 최신 웹 애플리케이션을 구축하기 위해 알아야 할 모든 것을 가르치는 새로운 과정입니다.
  • CSS 타임라인 은 CSS의 역사와 진화를 보여주는 타임라인입니다.
  • GitBar 는 풀 리퀘스트 리뷰를 보여주는 시스템 트레이 앱입니다.
  • Texture Lab 은 모든 텍스트에서 게임용 인스턴트 텍스처를 생성합니다.
  • Totems 는 맞춤형 스탠드와 지지대를 제작하는 스튜디오입니다.
  • PeopletoNotion 은 한 번의 클릭으로 Notion에 LinkedIn 프로필을 추가하는 Chrome 확장 프로그램입니다.
  • DeckDev 는 Magic: The Gathering의 덱 빌더입니다.
  • 기본 바로 가기 는 브라우저에서 키보드 바로 가기를 검색하는 도구입니다.

학습 리소스

날씬한 사회에서

보려고

읽다

라이브러리, 도구 및 구성 요소

새해 복 많이 받으세요 🎆 Reddit 또는 Discord 에서 놓친 것이 있으면 알려주세요.

 

원문 : 

https://svelte.dev/blog/whats-new-in-svelte-january-2023

728x90
728x90
반응형

1950년대 흑인 인권운동가

신문기자

여러나라의 언어들을 구사함

명예박사 학위 30개

칼립소 음악에 맞춰 춤을 추는 전문 댄서

토니상 후보 (미국 연극계에서 뛰어난 활약을 보인 배우에게 주는 상)

베스트셀러에 30권이나 오른 작가

여러 권의 시집을 발표한 시인으로 퓰리처상 후보에 등극

 

이 많은걸 마야 안젤루 한 사람이 했던 일이다.

하나하나만 봐도 대단한데 저 많은걸 해낸 진정한 폴리매스가 아닐까 싶다.

 

All men are prepared to accomplish the incredible if their ideals are threatened.
모든 사람은 자신의 이상이 위협받을 때 놀라운 일을 해낼 준비가 되어 있다.

At 50, I began to know who I was. It was like waking up to myself.
50살 때, 나는 내가 누구인지 알기 시작했다. 마치 나 자신에게 깨어난 것 같았다.

I've learned that people will forget what you said, said people will forget what you did, but people will never forget how you made them feel.
나는 사람들이 당신이 말한 것과 당신이 한 일을 잊을 것이라고 말했지만 당신이 그들에게 어떤 감정을 주었는지는 결코 잊지 않을 것임을 배웠다.


If you find it in your heart to care for somebody else, you will have succeeded.
다른 사람을 돌보는 것이 마음에서 우러나온다면, 당신은 성공할 것이다.

I'm always disappointed when people don't live up to their potential. I know that a number of people look down on themselves and consequently on everybody who looks like them. But that, too, can change.
나는 사람들이 그들의 잠재력에 부응하지 못할 때 항상 실망한다. 나는 많은 사람들이 자신들을 얕잡아 보고 결과적으로 자신들을 닮은 모든 사람들을 깔본다는 것을 알고 있다. 하지만 그것 역시 변할 수 있다.

It's good to remember that in crises, natural crises, human beings forget for awhile their ignorances, their biases, their prejudices. For a little while, neighbors help neighbors and strangers help strangers.
위기나 자연적인 위기에서 인간은 자신의 무식함, 편견, 편견을 잠시 잊고 있다는 사실을 기억하는 것은 좋은 일이다. 잠시 동안 이웃은 이웃을 돕고 낯선 사람은 낯선 사람을 돕는다.

Modesty is a learned affectation. And as soon as life slams the modest person against the wall, that modesty drops.
겸손은 배운 체하는 것이다. 그리고 삶이 겸손한 사람을 벽에 기대게 하는 순간, 그 겸손은 떨어진다.

In the flush of love's light, we dare be brave. And suddenly we see that love costs all we are, and will ever be. Yet it is only love which sets us free.
사랑의 빛이 비치는 곳에서 우리는 감히 용기를 낸다. 그리고 갑자기 우리는 사랑이 우리 모두를 희생시키고 앞으로도 그럴 것이라는 것을 알게 된다. 그러나 우리를 자유롭게 해주는 것은 오직 사랑이다.

728x90

'명언들모음' 카테고리의 다른 글

[명언] Jeff Atwood  (0) 2023.01.31
[명언] 당신이 무언가를 할 때 망설여진다면..  (0) 2023.01.11
728x90
반응형

Rust는 어떤 면에서는 굉장합니다. 그러나 빠르게 움직여야 하는 스타트업을 선택하기 전에 두 번 고려하세요.


나는 프로그래밍 언어에 대한 성전을 시작하거나 시작하고 싶지 않기 때문에 이 글을 쓰는 것을 주저했습니다. (불길한 미끼를 없애기 위해 Visual Basic은 최고의 언어입니다!) 그러나 많은 사람들이 Rust에 대한 나의 경험과 프로젝트에 Rust를 선택해야 하는지 여부를 묻습니다. 그래서 저는 빠르게 움직이고 팀을 확장하는 것이 정말 중요한 스타트업 환경에서 Rust를 사용하는 것에 대해 제가 본 장단점을 공유하고 싶습니다.

나는 특정한 것에 대해 Rust의 팬임을 분명히 하고 싶습니다 . 이 게시물은 Rust가 언어로서 얼마나 나쁜지에 대한 것이 아닙니다. 그러나 내가 말하고 싶은 것은 Rust를 사용하는 것이 당신이 빨리 움직이려고 한다면 주요 요인이 될 수 있는 사소하지 않은 생산성 타격을 거의 확실하게 수반할 것이라는 점입니다. 속도 영향이 회사 및 제품에 대한 언어의 이점만큼 가치가 있는지 신중하게 평가하십시오.

바로 앞에, Rust는 설계된 일에 매우 뛰어나며 프로젝트에 Rust의 특정 이점(고성능, 초강력 타이핑, 가비지 수집이 필요 없는 시스템 언어 등)이 필요한 경우에 말해야 합니다. 그런 다음 Rust는 훌륭한 선택입니다. 그러나 저는 Rust가 그다지 적합하지 않은 상황에서 자주 사용되며 팀은 많은 이점을 얻지 못한 채 Rust의 복잡성과 오버헤드의 대가를 지불한다고 생각합니다.

Rust에 대한 나의 주된 경험은 이전 스타트업에서 2년 조금 넘게 일하면서 얻은 것입니다. 이 프로젝트는 클라우드 기반 SaaS 제품으로, 거의 기존의 CRUD 앱에 불과했습니다. 데이터베이스 앞에 REST 및 gRPC API 엔드포인트를 제공하는 마이크로서비스 집합과 기타 일부 백-서비스입니다. 최종 마이크로서비스(자체는 Rust와 Python의 조합으로 구현됨). Rust는 주로 회사 창립자 두 명이 Rust 전문가였기 때문에 사용되었습니다. 시간이 지나면서 우리는 팀을 상당히 성장시켰고(엔지니어링 인원을 거의 10배 늘림) 코드베이스의 크기와 복잡성도 상당히 커졌습니다.

팀과 코드베이스가 성장함에 따라 시간이 지남에 따라 Rust를 계속 사용하는 데 점점 더 많은 세금을 내고 있다고 느꼈습니다. 때때로 개발이 느렸고, 새로운 기능을 출시하는 데 예상보다 오래 걸렸으며, 팀은 Rust를 사용하기로 한 초기 결정으로 인해 실질적인 생산성 저하를 느꼈습니다. 다른 언어로 코드를 다시 작성하면 장기적으로 개발이 훨씬 더 민첩해지고 전달 시간이 빨라지지만 주요 재작성 작업을 위한 시간을 찾는 것은 매우 어려웠을 것입니다. 그래서 우리는 총알을 깨물고 많은 양의 코드를 다시 작성하기로 결정하지 않는 한 Rust에 갇혀 있었습니다.

녹은 얇게 썬 빵 이후로 가장 좋은 것으로 여겨졌는데 왜 우리에게는 잘 작동하지 않았습니까?

Rust는 엄청난 학습 곡선을 가지고 있습니다.

나는 내 경력에서 수십 개의 언어로 작업했으며 거의 ​​예외 없이 대부분의 현대적이고 절차적인 언어(C++, Go, Python, Java 등)는 모두 기본 개념 측면에서 매우 유사합니다. 각 언어에는 차이점이 있지만 일반적으로 언어마다 다른 몇 가지 주요 패턴을 학습한 다음 매우 빠르게 생산적일 수 있습니다.그러나 Rust를 사용하려면 배워야 합니다.완전히 새로운 아이디어— 수명, 소유권 및 차용 검사기와 같은 것. 이는 다른 공통 언어로 작업하는 대부분의 사람들에게 친숙한 개념이 아니며 숙련된 프로그래머에게도 상당히 가파른 학습 곡선이 있습니다.

이러한 "새로운" 아이디어 중 일부는 물론 다른 언어, 특히 기능적인 언어에 존재하지만 Rust는 이러한 아이디어를 "주류" 언어 설정으로 가져오므로 많은 Rust 초보자에게 생소할 것입니다.

내가 함께 일했던 가장 똑똑하고 경험이 많은 개발자였음에도 불구하고 팀의 많은 사람들(나 자신 포함)은 Rust에서 특정 작업을 수행하는 정식 방법, 컴파일러에서 종종 난해한 오류 메시지를 파악하는 방법 또는 핵심 라이브러리가 작동하는 방식을 이해하는 방법(자세한 내용은 아래 참조). 우리는 팀이 지식과 ​​전문 지식을 공유하는 데 도움이 되도록 매주 "Rust 학습" 세션을 갖기 시작했습니다. 모두가 느린 개발 속도를 느꼈기 때문에 이것은 모두 팀의 생산성과 사기를 크게 떨어뜨렸습니다.

소프트웨어 팀에서 새로운 언어를 채택하는 것이 어떤 것인지 비교하기 위해 Google의 한 팀은 C++에서 Go로 완전히 전환한 최초의 팀 중 하나였습니다. 15명 정도의 팀이 처음으로 Go로 꽤 편안하게 코딩했습니다. Rust를 사용하면 매일 몇 달 동안 언어로 작업한 후에도 팀의 대부분의 사람들이 완전히 유능하다고 느끼지 못했습니다. 많은 개발자들이 자신의 기능이 착륙하는 데 예상보다 오래 걸리고 Rust를 이해하는 데 너무 오랜 시간을 소비하고 있다는 사실에 종종 당혹스럽다고 말했습니다.

Rust가 해결하려는 문제를 해결하는 다른 방법이 있습니다.

위에서 언급했듯이 우리가 구축한 서비스는 상당히 간단한 CRUD 앱이었습니다. 이 서비스에 대한 예상 부하는 이 특정 시스템의 수명 동안 최대 초당 몇 개의 쿼리를 넘지 않을 것입니다. 이 서비스는 실행하는 데 많은 시간이 걸릴 수 있는 상당히 정교한 데이터 처리 파이프라인의 프런트엔드였으므로 서비스 자체가 성능 병목 현상이 될 것으로 예상되지 않았습니다. Python과 같은 기존 언어가 좋은 성능을 제공하는 데 문제가 있을 것이라는 특별한 우려는 없었습니다. 웹 대면 서비스가 처리해야 하는 것 외에 특별한 안전이나 동시성 요구 사항은 없었습니다. 우리가 Rust를 사용한 유일한 이유는 시스템의 원래 작성자가 Rust 전문가였기 때문이지 이런 종류의 서비스를 구축하는 데 특히 적합했기 때문이 아닙니다.

Rust는 개발자 생산성보다 안전이 더 중요하다는 결정을 내렸습니다. 이것은 OS 커널에서 코드를 작성하거나 메모리가 제한된 임베디드 시스템과 같은 많은 상황에서 올바른 절충안이지만 모든 경우에 올바른 절충안이라고 생각하지 않습니다. 특히 속도가 중요한 스타트업에서는 그렇지 않습니다. 나는 실용주의자입니다. 팀의 모든 구성원이 이러한 문제를 완전히 방지하도록 설계된 언어를 사용하여 생산성이 4배 저하되는 것보다 팀에서 가끔 발생하는 메모리 누수 또는 Python 또는 Go로 작성된 코드의 유형 오류를 디버깅하는 데 시간을 할애하는 편이 낫 습니다 . .

위에서 언급했듯이 Google 팀은 전적으로 Go로 서비스를 구축했으며 시간이 지남에 따라 8억 명 이상의 사용자와 Google 검색 QPS의 4배 정도를 지원하는 수준으로 성장했습니다. 이 서비스를 구축하고 실행하는 동안 Go의 유형 시스템이나 가비지 컬렉터로 인해 발생한 문제에 부딪힌 횟수는 한 손으로 셀 수 있습니다. 기본적으로 Rust가 피하도록 설계된 문제는 좋은 테스트, 좋은 린팅, 좋은 코드 검토, 좋은 모니터링 등 다른 방법으로 해결할 수 있습니다. 물론 모든 소프트웨어 프로젝트가 이러한 사치를 누리는 것은 아니므로 다른 상황에서는 Rust가 좋은 선택이 될 수 있다고 상상할 수 있습니다.

Rust 개발자를 고용하는 데 어려움을 겪을 것입니다.

우리는 이 회사에 있는 동안 수많은 사람들을 고용했지만 엔지니어링 팀에 합류한 60명 이상의 사람들 중 약 2~3명만이 Rust에 대한 이전 경험이 있었습니다. 이것은 Rust 개발자를 찾기 위한 노력이 부족해서가 아닙니다 — 그들은 단지 거기에 없을 뿐입니다. (동일한 이유로 우리는 Rust 로만 코딩하기를 원하는 사람들을 고용하는 것을 주저했습니다 . 언어 및 기타 기술 선택이 민첩한 방식으로 이루어져야 하는 스타트업 환경에서 설정하는 것은 나쁜 기대라고 생각하기 때문입니다.) Rust가 더 주류가 됨에 따라 Rust 개발 인재의 수는 시간이 지남에 따라 변할 것입니다.

또 다른 두 번째 요인은 Rust를 사용하면 팀에서 Rust를 아는 사람들과 그렇지 않은 사람들 사이에 분열이 생길 것이 거의 확실하다는 것입니다. 우리는 이 서비스를 위해 "난해한" 프로그래밍 언어를 선택했기 때문에 기능 구축, 생산 문제 디버깅 등에 도움이 되었을 수 있는 회사의 다른 엔지니어들은 대체로 도움을 줄 수 없었습니다. Rust 코드베이스의 꼬리. 엔지니어링 팀의 이러한 대체 가능성 부족은 빠르게 움직이고 팀의 모든 구성원의 결합된 강점을 활용하려고 할 때 실질적인 문제가 될 수 있습니다. 내 경험상, 사람들은 일반적으로 C++와 Python 같은 언어 사이를 이동하는 데 거의 어려움이 없지만 Rust는 충분히 새롭고 복잡해서 사람들이 함께 작업하는 데 장벽이 됩니다.

라이브러리와 문서는 미성숙합니다.

이것은 (희망합니다!) 시간이 지나면 해결되겠지만 Go와 비교할 때 Rust의 라이브러리와 문서화 생태계는 믿을 수 없을 정도로 미숙합니다. 이제 Go는 전 세계에 출시되기 전에 Google의 전체 전담 팀에서 개발하고 지원했다는 이점이 있으므로 문서와 라이브러리가 상당히 세련되었습니다. 이에 비해 Rust는 오랫동안 진행 중인 작업처럼 느껴졌습니다. 많은 인기 있는 라이브러리에 대한 문서가 매우 드물고 사용 방법을 이해하기 위해 특정 라이브러리 의 소스 코드 를 읽어야 하는 경우가 많습니다 . 이것은 나쁘다.

팀의 Rust 사과론자들은 종종 "async/await는 여전히 정말 새롭습니다." 및 "예, 해당 라이브러리에 대한 문서가 부족합니다."와 같은 말을 하지만 이러한 단점은 팀에 상당한 영향을 미쳤습니다. 우리는 서비스의 웹 프레임워크로 Actix를 채택함으로써 초기에 큰 실수를 저질렀습니다. 그 결정은 아무도 수정 방법을 알아낼 수 없는 라이브러리 깊숙이 묻혀 있는 버그와 문제에 부딪히면서 엄청난 고통과 괴로움을 초래했습니다. (공평하게 말하면 이것은 몇 년 전의 일이고 지금은 상황이 개선되었을 수 있습니다.)

물론 이런 종류의 미숙함은 실제로 Rust에만 국한된 것은 아니지만 팀이 지불해야 하는 세금에 해당합니다. 핵심 언어 문서와 자습서가 아무리 훌륭하더라도 라이브러리 사용 방법을 알 수 없다면 별 문제가 되지 않습니다(물론 처음부터 모든 것을 작성하려는 경우가 아니라면).

Rust는 새로운 기능을 대략적으로 만드는 것을 매우 어렵게 만듭니다.

나는 다른 사람에 대해 모르지만 적어도 나에게는 새로운 기능을 구축할 때 일반적으로 모든 데이터 유형, API 및 기타 세부 정보가 먼저 작동하지 않습니다. 나는 종종 몇 가지 기본 아이디어가 작동하도록 노력하고 일이 어떻게 작동해야 하는지에 대한 내 가정이 다소 정확한지 확인하려고 코드를 작성합니다. 예를 들어 Python에서 이 작업을 수행하는 것은 매우 쉽습니다. 타이핑과 같은 작업을 빠르고 느슨하게 수행할 수 있고 아이디어를 대략적으로 작성하는 동안 특정 코드 경로가 손상되더라도 걱정할 필요가 없기 때문입니다. 나중에 돌아가서 모든 것을 깔끔하게 만들고 모든 유형 오류를 수정하고 모든 테스트를 작성할 수 있습니다.

Rust에서 이런 종류의 "초안 코딩"은 매우 어렵습니다. 왜냐하면 컴파일러 는 유형 및 수명 검사를 통과하지 못하는 빌어먹을 모든 것에 대해 불평할 수 있고 불평할 것이기 때문 입니다. 이것은 생산 준비가 된 최종 구현을 구축해야 할 때 완벽하게 이해되지만 아이디어를 테스트하거나 기본 기반을 마련하기 위해 무언가를 함께 짜내려고 할 때 절대적으로 짜증납니다. 매크로는 어느 정도 도움 이 unimplemented!되지만 여전히 컴파일하기 전에 스택에서 모든 유형을 확인해야 합니다.

정말 짜증나는 것은 로드 베어링 인터페이스의 유형 서명을 변경해야 하고 유형이 사용되는 모든 장소를 변경하는 데 시간을 소비하여 무언가에 대한 초기 찌르기가 가능한지 확인하는 것입니다. 그런 다음 다시 변경해야 한다는 것을 깨달았을 때 모든 작업을 다시 실행합니다.

러스트는 무엇을 잘하나요?

Rust에 대해 제가 좋아하는 점과 다른 언어로 갖고 싶은 Rust의 기능이 분명히 있습니다. match구문이 훌륭합니다 . ,  특성은 정말 강력하며 Option연산자 는 오류를 처리하는 우아한 방법입니다. 이러한 아이디어 중 많은 부분이 다른 언어로 된 대응물을 가지고 있지만 Rust의 접근 방식은 특히 우아합니다.ResultError?

나는 높은 수준의 성능과 안전성이 필요하고 빠르게 성장하는 전체 팀과 함께 코드의 주요 부분을 빠르게 발전시켜야 할 필요성에 대해 크게 걱정하지 않는 프로젝트에 Rust를 절대적으로 사용할 것입니다. 개별 프로젝트나 매우 작은(예: 2-3명) 팀의 경우 Rust가 적합할 것입니다. Rust는 성능과 안전이 가장 중요한 커널 모듈, 펌웨어, 게임 엔진 등과 같은 것들과 출하 전에 철저한 테스트를 수행하기 어려울 수 있는 상황에서 훌륭한 선택입니다

[원본]

https://mdwdotla.medium.com/using-rust-at-a-startup-a-cautionary-tale-42ab823d9454

728x90
728x90
반응형

학습 시작

728x90

+ Recent posts