[잡담] rust로 프로그래밍 대회를 하는게 가능할까요?

  • Neon
    Neon

    안녕하세요.

    어지간한 큰 온라인 대회는 꼬박꼬박 참여하곤 했었는데, 요즘은 좀 바빠서 열심히 준비하기가 쉽지 않더라구요. 그래서 뭔가 다른걸 같이 병행해서 시도해보자... 는 생각으로 rust로 프로그래밍 대회를 도전해보려고 합니다만... 이거 꽤 쉽지가 않네요.

    시험삼아 GCJ의 추천 qual-round 문제를 도전해봤습니다. 코드는 여기에 있습니다.

    코딩을 하면서 느낀 몇가지 장단점을 적어보자면...

    굳이 골라보는 장점

    일단 C/C++과 비교가능한 수준의 속도를 장점으로 꼽을 수 있겠습니다. 뭐 실제로 하드코어하게 비교해본 것은 아닙니다만 컴파일하는데 드는 시간은 최적화 옵션(-O)를 기준으로 0.760초 걸렸고, large 데이터를 푸는 데 걸린 시간도 1.07초 걸렸습니다. C/C++로 동일한 로직을 구현한다고 가정해도 비슷한 수준의 시간이 걸리지 않을까 짐작해 봅니다.

    또한 아무래도 나중에 나온 언어인 만큼 각종 문법이 자연스럽게 들어갑니다. C++11에서 추가된 문법들이 다소 손에 익지 않기도 했고 기존 언어 문법과 생소해서 이상하다 싶은 부분이 조금 있었는데, rust에선 아직 그런 부분이 없었습니다.

    또 Debug라는 trait을 제공하는데, 이걸 활용하면 실행 중에 변수 내용을 확인하기가 간편합니다.

    자 그럼 단점 들어갑니다

    stdio 및 string 처리가 매우 제한적이고 번거롭다는 느낌이 들었습니다. 실패할 수 있는 대부분의 기능들이 Option 개념의 구조체를 반환하기 때문에 추가로 unwrap을 호출해줘야만 했습니다. string의 경우에도 그 자체로는 index 접근을 허용하지 않았고, chars() 등의 메소드를 호출해서 명시적으로 Vec로 변환해야만 했습니다. STL string이 간편하게 index 접근이 가능한 것과 비교해보면 너무 번거로웠습니다.

    각종 함수로 변수를 호출할 때 &을 빼먹으면 변수를 더이상 쓸 수 없게 됩니다. 의외로 실수할 여지가 많아서 힘들더군요. 하지만 C에서도 최적화를 하다 보면 가능한 모든 곳에 &reference를 사용하니만큼 익숙해지면 해결될 문제 같았습니다.

    stdin에서 한줄 읽어서 원하는 타입으로 parse하는 가능을 만들어보고 싶어서 read_line이라는 함수를 만들어봤는데요, 각종 type 관련 제약을 모두 컴파일 타임에 분석 가능한 형태로 코드에 명시해야 한다는게 힘들었습니다. 저는 실제로는 String과 i32만 사용했으니 해당 타입에 대해서만 검사를 해도 좋을 것 같은데, 왜 임의의 타입에 대해 모두 성립하는 무언가를 요구하는 것인가... 실제 쓰는 타입에 대해서만 검사하는 C++의 template에 익숙해져 있던 저에게는 그냥 귀찮고 번거롭기만 한 기능이었습니다.

    Type 체크가 너무 빡빡한 것도 불만이었습니다. usize와 i32 값을 비교하는데 왜 명시적 캐스팅을 해 줘야 하는 건지... ㅠㅠ (u32였으면 그러지 않아도 됐을까요? 잘 모르겠습니다)

    fn으로 선언하는 함수와 달리 람다식 함수는 자동으로 변수를 capture하게 되는데요, 이 capture의 scope가 또한 괴랄합니다. 코드에서 chk라는 람다식을 선언하는데, 여기서 빌려가는 candi 변수는 해당 람다식이 존재하는 범위에서는 더이상 사용할 수 없는 값이 되어버립니다. 그 전에 사용하고 싶으면 아마도 람다식의 유효 범위를 줄여야만 할텐데, 아무래도 대회용 코딩에는 여러모로 번거롭기만 한 요소가 될 것 같습니다.

    그래서, 정리하자면

    야 이거 내가 쓸데없이 지뢰를 밟았구나. 빨리 빠져나가는 것이 좋겠어.

    (가차없는 지적질 환영합니다. 제가 겪은 문제들을 해결해줄 rust 고수님의 손길이 필요합니다)


    5년 전
2개의 댓글이 있습니다.
  • windless
    windless
    • usize와 i32: 제 생각에 이건 변환이 명시적으로 되는게 더 좋은 것 같습니다. 왜냐하면 usize는 pointer-size이고, 아키텍쳐에 따라 i32와 크기가 다를 수 있기 때문입니다 (The pointer-sized unsigned integer type).

    • 다른 부분들은 전부 동의합니다(..) Rust의 ownership 개념은 쉽게 이해하고 프로그래밍할 수 있는 난이도가 아닌 것 같습니다. Ownership을 formal하게 정의하려는 시도들이 있지만 (https://doc.rust-lang.org/nomicon/ 그리고 MPI-SWS의 연구자들), 생각보다 매우 어려운 문제라는데 다들 동의하는 것 같습니다.


    5년 전 link
  • KimJJ
    KimJJ

    usize와 u32가 다른 타입인 이유는 윗분이 말씀하셨듯 pointer-width이기 때문입니다.

    Rust의 스트링 처리는 C++보다는 Python의 그것을 생각하는 편이 편할 겁니다.


    5년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.