트랙
/
Elixir
Elixir
/
연습 문제
/
무선 조종 자동차
무선 조종 자동차

무선 조종 자동차

학습 연습 문제

소개

구조체

구조체는 맵 위에 구축된 확장 기능으로, 컴파일 시점 검사와 기본값을 제공해요. 구조체는 정의된 모듈의 이름을 따라 이름이 붙어요. 구조체를 정의하려면 defstruct 구문을 사용해요. 이 구문은 보통 모듈 정의 바로 뒤에 와요. defstruct는 아톰 리스트(nil 기본값용)나 키워드 리스트(지정된 기본값용)를 받아요. 기본값이 없는 필드는 기본값이 있는 필드보다 먼저 와야 해요.

defmodule Plane do
  defstruct [:engine, wings: 2]
end

plane = %Plane{}
# => %Plane{engine: nil, wings: 2}

필드 접근과 업데이트

구조체는 맵을 기반으로 하기 때문에, 대부분의 맵 함수를 사용해 값을 가져오고 조작할 수 있어요. _Access Behaviour_는 구조체에 대해 구현되어 있지 않아요. 대신 구조체 필드에 접근하려면 정적 접근 연산자 .를 사용하는 것이 좋아요.

  • 필드 값 가져오기:

    plane = %Plane{}
    plane.engine
    # => nil
    Map.fetch(plane, :wings)
    # => {:ok, 2}
    
  • 필드 값 업데이트

    plane = %Plane{}
    %{plane | wings: 4}
    # => %Plane{engine: nil, wings: 4}
    

패턴 매칭

구조체는 구조체 이름을 사용하거나 사용하지 않고 패턴 매칭에 사용할 수 있어요.

plane = %Plane{}
%Plane{wings: wings} = plane
%{wings: wings} = plane

패턴에 구조체 이름을 포함하면, 왼쪽과 오른쪽이 같은 타입의 구조체인지 확인할 수 있어요.

defmodule Helicopter do
  defstruct [:engine, rotors: 1]
end

%Plane{} = %Helicopter{}
# => (MatchError) no match of right hand side value: %Helicopter{engine: nil, rotors: 1}

필드 값 초기화 강제

@enforce_keys 모듈 속성을 필드 키 리스트와 함께 사용하면, 구조체가 생성될 때 값이 초기화되도록 할 수 있어요. 키가 리스트에 없으면, 위 예제에서 본 것처럼 값이 nil이 돼요. 강제된 키가 초기화되지 않으면 오류가 발생해요.

defmodule User do
  @enforce_keys [:username]
  defstruct [:username]
end

%User{}
# => (ArgumentError) the following keys must also be given when building struct User: [:username]

지침

이 연습 문제에서는 드디어 돈을 모아서 장만한 무선 조종 자동차를 가지고 놀아볼 거예요.

자동차는 완전히 충전된(100%) 배터리로 시작해요. 리모컨으로 자동차를 운전할 때마다 20미터를 이동하고 배터리를 1퍼센트 소모해요. 자동차의 별명은 자동차를 만들기 전까지는 알 수 없어요.

무선 조종 자동차에는 두 가지 정보를 보여주는 멋진 LED 디스플레이가 있어요:

  • 지금까지 이동한 총 거리, "<METERS> meters"로 표시돼요.
  • 남은 배터리 잔량, "Battery at <PERCENTAGE>%"로 표시돼요.

배터리가 0%라면 더 이상 자동차를 운전할 수 없고, 배터리 표시에는 "Battery empty"가 나타나요.

1. 새 무선 조종 자동차 만들기

새 무선 조종 자동차 구조체를 반환하도록 RemoteControlCar.new/0 함수를 구현해요:

RemoteControlCar.new()
# => %RemoteControlCar{
#      battery_percentage: 100,
#      distance_driven_in_meters: 0,
#      nickname: "none"
#    }

별명은 구조체에 반드시 필요한데, 값은 구조체가 아니라 new 함수에서 초기화해야 해요.

2. 별명이 있는 새 무선 조종 자동차 만들기

전달받은 별명을 가진 새 무선 조종 자동차 구조체를 반환하도록 RemoteControlCar.new/1 함수를 구현해요:

RemoteControlCar.new("Blue")
# => %RemoteControlCar{
#      battery_percentage: 100,
#      distance_driven_in_meters: 0,
#      nickname: "Blue"
#    }

3. 거리 표시하기

LED 디스플레이에 표시되는 대로 거리를 반환하도록 RemoteControlCar.display_distance/1 함수를 구현해요:

car = RemoteControlCar.new()
RemoteControlCar.display_distance(car)
# => "0 meters"

이 함수가 인자로 RemoteControlCar 구조체만 받도록 해요.

4. 배터리 잔량 표시하기

LED 디스플레이에 표시되는 대로 배터리 잔량을 반환하도록 RemoteControlCar.display_battery/1 함수를 구현해요:

car = RemoteControlCar.new()
RemoteControlCar.display_battery(car)
# => "Battery at 100%"

이 함수가 인자로 RemoteControlCar 구조체만 받도록 해요. 배터리가 0%라면 배터리 표시에는 "Battery empty"가 나타나요.

5. 운전하면 배터리와 이동 거리가 바뀌어요

다음을 수행하는 RemoteControlCar.drive/1 함수를 구현해요:

  • 이동한 미터 수를 20만큼 늘려요
  • 배터리를 1% 소모해요
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()

# => %RemoteControlCar{
#      battery_percentage: 99,
#      distance_driven_in_meters: 20,
#      nickname: "Red"
#    }

이 함수가 인자로 RemoteControlCar 구조체만 받도록 해요.

6. 방전된 배터리로 운전하는 경우 처리하기

배터리가 방전된(0%) 경우에는 이동 거리도 늘리지 않고 배터리 잔량도 줄이지 않도록 RemoteControlCar.drive/1 함수를 수정해요:

%RemoteControlCar{
  battery_percentage: 0,
  distance_driven_in_meters: 1980,
  nickname: "Red"
}
|> RemoteControlCar.drive()

# => %RemoteControlCar{
#      battery_percentage: 0,
#      distance_driven_in_meters: 1980,
#      nickname: "Red"
#    }
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
Elixir Exercism

무선 조종 자동차 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 Elixir 트랙을 개념 58개연습 문제 168개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.