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

+ Recent posts