구글에서 크로스 플랫폼 개발 툴킷으로 제공하고 있는 Flutter는 Dart라는 객체지향 언어를 사용합니다.
때문에 플러터를 배우려면 Dart 문법을 지나칠 수가 없겠죠?
Dart는 C계열 언어와 문법이 비슷해서 프로그래밍을 경험해본 사람은 쉽게 배울 수 있는 언어라고 생각합니다.
이번 시간에는 Dart언어의 syntax를 다뤄보도록 하겠습니다.
다른 언어에 공통적으로 있는 syntax는 생략하거나 간략 설명하는 방식으로 진행되겠습니다.
1. 타입
모든 것이 객체
처음은 언어 소개답게 타입부터 시작해보겠습니다.
먼저, Dart에서는
null
을 제외한 모든 것이 Object입니다.1, ‘a’ 같은 값들도 객체로 존재하게 됩니다.
null
은 별도로 Null
이라는 클래스의 객체로 존재합니다.선언자 알아보기
const
는 다른 언어에서도 많이 제공되는 선언자로 어떤 변수의 값을 일정하게 만들기 위해 사용됩니다.그런데,
const
는 초기화와 할당이 동시에 이뤄져야 합니다.반면에
final
선언자는 초기화와 할당을 동시에 하지 않아도 값을 일정하게 만들어주는 선언자라고 할 수 있겠습니다. 예시를 살펴볼까요?그렇다면
dynamic
은 무엇일까요?다음 예시를 보면 이해가 되실 것 같습니다.
final
과 dynamic
의 차이는 한 번만 할당되냐 그렇지 않냐에 있습니다.dynamic
은 또 다른 특징이 있습니다. 이번에는 var
와 비교를 해보겠습니다.dynamic
과 var
모두 여러 번 할당이 가능하지만 var
는 선언했을 때 할당받은 값의 타입을 갖게 됩니다.때문에 9번째 줄처럼
String
을 할당할 수 없게 되죠.재밌는건
var
도 선언과 할당을 동시에 하지 않고 나중에 할당할 경우 dynamic
과 똑같이 다른 타입의 값을 할당해줄 수 있게 됩니다.var
선언자를 사용할 때는 이 점을 유의하는게 좋겠습니다.한마디로
dynamic
은 계속 타입을 추론해 할당할 수 있도록 하는 선언자입니다. 정말 dynamic
하죠?이
dynamic
은 보통 JSON을 처리할때 많이 사용됩니다.예시에서
Map
타입은 키와 값을 가지는 컬렉션 타입입니다.타입과 관련해 정리를 해보면 다음과 같습니다.
🗒️정리
- Dart에서는
null
을 제외한 모든 것이 Object이다.null
역시Null
클래스의 객체이다.
final
,dynamic
같은 동적 선언자 및 타입을 제공한다.
2. 함수
파라미터
Dart에서는 함수 파라미터를 표현하는데 몇 가지 옵션을 제공하고 있습니다.
하나씩 살펴보겠습니다.
- 이름 지정
9번째 줄 코드처럼 파라미터 이름을 지정해서 값을 넣어줄 수가 있는데
이름을 지정하기 위해 파라미터를 중괄호
{}
로 감싸주어야 합니다.10번째 줄 코드와 같이 이름을 지정해서 값을 넣지 않았다면 기본적으로 할당 받은 값을 가지게 됩니다.
- 선택형 위치 지정
이번엔 파라미터에 중괄호가 아니고 대괄호
[]
가 보입니다.대괄호로 감싸진 파라미터는 선택적으로 사용되는 파라미터를 의미합니다.
12번째 줄 코드처럼 마지막 파라미터인 c에 값을 넘기지 않아도 함수 호출이 가능한 것을 알 수 있습니다.
이때 c의 타입에
?
가 붙었는데, Dart에서 ?
는 해당 변수가 null
을 가질 수 있음을 의미합니다.이는
null
값으로 인해 발생할 수 있는 문제를 해결하는 Null Safety
개념과 관련이 있는데 추후에 다뤄보도록 하겠습니다.이름 지정, 선택형 지정 파라미터는 클래스에서 주로 사용되는데 뒷부분에서 더 자세히 다루도록 하겠습니다.
함수형 프로그래밍
Dart는 함수형 프로그래밍(FP) 특징도 갖고 있는 언어입니다.
아래 예시와 같이 Dart에서는 함수를 값으로 사용할 수 있습니다.
Dart에는
List
, Set
, Map
타입의 컬렉션이 존재합니다.컬렉션은 리스트처럼 여러 데이터를 원소로 갖는 자료구조라고 보면 되겠습니다.
이 컬렉션은
Iterable
타입 객체로써 존재하며 Iterable
클래스 메소드를 사용할 수 있습니다.이 컬렉션과 관련된 함수형 프로그래밍 형식의 코드를 살펴보겠습니다.
간단하게 리스트의 원소를 순차적으로 출력하는 코드입니다.
이것을 for문 없이 함수형 프로그래밍 형식으로 다시 작성해보겠습니다.
컬렉션에서 사용되는
forEach
메소드는 파라미터로 함수를 받습니다.그리고, 컬렉션 안의 원소들을 하나씩 꺼내 파라미터로 들어온 함수를 실행하게 됩니다.
자바스크립트나 파이썬을 경험해 보신 분들은 익숙할 것이라 생각합니다.
이번엔 더 특수한 상황을 살펴보겠습니다.
이번엔 컬렉션에서 짝수만 출력하는 코드입니다.
where
메소드로 조건에 부합한 원소를 구성하는 새로운 Iterable
을 생성하고 그것에 대해 forEach
메소드를 진행하게 됩니다.하나만 더 살펴볼까요?
이번에는 컬렉션에서 가장 큰 값을 출력하는 상황입니다.
이런 경우 컬렉션의
reduce
라는 메소드로 해결할 수 있습니다.reduce
는 원소를 순차적으로 꺼내 특정 조건의 누적된 값을 반환하는 메소드인데 다음 예시를 통해 더 자세하게 살펴보겠습니다.16~20번째 줄 코드는 위의 예시와 동일한 작업을 수행하지만 중간 과정을 출력한 것입니다.
콘솔에서 볼 수 있듯이 원소를 순차적으로 꺼내
max
함수의 결과를 반환하게 됩니다.이처럼 컬렉션 함수를 이용하면 간결한 코드로 구현할 수 있습니다.
함수와 관련해 정리를 해보면 다음과 같습니다.
🗒️정리
- 파라미터와 관련해서 다양한 옵션을 제공하고 있다.
- Dart에서 함수는 값으로써 사용되는 일급함수이다.
3. 클래스
No Overloading
자바나 C++에서는 이름은 같지만 형식이 다른 생성자 오버로딩을 지원합니다.
반면, Dart는 오버로딩을 지원하지 않습니다.
- 이름 있는 생성자
예시를 먼저 살펴보겠습니다.
위의 예시처럼
생성자.이름
형식으로 생성자에 이름을 부여할 수 있습니다.그래서 기본 생성자는 사실 이름이 없는 생성자라고 볼 수 있습니다.
그런데, 생성자를 하나만 써주고 싶은 기분이 들죠? 다른 방법은 없을까요?
앞에서 다뤘던 지정 파라미터가 이를 해결해 줄 수 있습니다.
- 지정 파라미터
선택형 지정 파라미터에 연산자를 받게끔 변경된 상태입니다.
이렇게 지정 파라미터를 통해 하나의 생성자에서 오버로딩이 구현된 것처럼 만들수 있겠습니다.
어찌보면 지정 파라미터가 있으니까 오버로딩을 굳이 지원하지 않나봅니다.
접근 제어자
Dart에는
public
, private
같은 접근 제어자 키워드가 없지만 매우 간단하게 표현할 수 있습니다.위의 예시에서 볼 수 있듯이 변수 이름에
_(밑줄)
의 유무에 따라 public
, private
가 결정됩니다.밑줄이 있는 변수인 health는
private
이기 때문에 외부에서 접근할 수 없게 됩니다.클래스와 관련해 정리를 해보면 다음과 같습니다.
🗒️정리
- Dart는 오버로딩을 지원하지 않는다. 대신에 이름이 있는 생성자를 사용한다.
public
,private
과 같은 접근 제어자가 없고 다른 방식을 취한다.
참고문헌: 에릭 윈드밀, Flutter in Action
아래의 링크에서 Dart 언어를 다뤄보실 수 있습니다.