출처: https://at0z.tistory.com/155
기본 문법
(티스토리 코드블럭은 Dart를 지원하지 않아 우선 java로 표기합니다)
주석
//주석 /** * 주석 **/ /// 문서주석
문장
명령 단위. 세미콜론 ;으로 끝난다.
변수
data를 담는 상자. 종류는 type, 자료형이라고 함.dart는 int, double, String, bool을 기본 제공.사용자가 직접 타입을 정의할 수 있음.
String name; name = "홍길동"; name = '홍길동'; //따옴표 종류 상관없이 가능
int, double은 num type의 하위 집합이라 int, double 대신 num으로 선언 가능.
num 타입에는 int, double 대입 가능.
int a = 1; double b = 2.0; num c = a; c = b;
타입 추론
위와 같이 type을 직접 명시하지 않고, var로 대체할 수 있음. (JS같이)
일반적으로 많이 사용.
var i = 10; //int var d = 10.0 //double var s = "hello"; //String var b = true; //boolean
상수 final, const
값이 변하지 않는 경우는 상수 사용. 선언시 final을 제일 앞에 붙이면 값이 수정되지 않음. 타입 생략 가능.
final String name = "홍길동"; final name = "홍길동";
산술 연산자
+, -, *, /(나누기 - double), ~/(몫 - int), %(나머지 - int) 사용 가능.
+의 경우 string concat에서도 사용.
증감 연산자
1씩 증가(++) 또는 1씩 감소(--). 후위(식++)/전위(++식) 연산 모두 가능.
비교 연산자
==, !=, >, <, >=, <= 사용 가능.
논리연산자
boolean 타입으로 결과 반환.
&&, ||, ==, !, != 사용 가능.
타입 검사
is를 사용.
[변수] is [type] => 같은 타입인지[변수] is! [type] => 다른 타입인지
int a = 1; if (a is int){~} if (a is! int){~}
형변환 (as)
type casting. as를 사용. 다른 타입끼리는 변환 불가. 상위 개념으로만 변환 가능.
특히, int, double은 num으로 묶여있지만 각자는 관계가 없어 형변화 불가.
var c = 10.0 num n = c as num; num n = c //as num 생략 가능 int d = c as int; //error
함수
function. 코드 묶음 단위.
함수 형태
입력 받는 문자 : 매개변수 parameter실제로 입력받는 값 : 인수 argument반환되는 값 : 반환값 Return
=> 일반적인 C문법과 동일하다.
변수 앞에 $를 붙여 문자열 내에 변수 삽입 가능. (파이썬에서 {}사용하는 것과 같다)
또한, ${~~}부분에 표현식 사용 가능.
String name = "이순신"; int age = 20; void main(){ print('$name은 $age살 입니다.'); print("$name은 ${name.length}글자 입니다."); }
함수와 메서드
최상위 함수 : class 밖에 작성하는 함수. 일반적으로 말하는 함수들. (main method처럼 가장 밖에 작성). 어디에서나 호출 가능.
method : class 내부에 작성하는 함수. 정의된 class에 관계된 기능을 수행. Static이 붙은 method는 정적 메서드가 되어 최상위 함수처럼 사용 가능.
익명 함수
anonymouse function.
([인수명]) { [동작 or Return 값] }
(number) { return number % 2 == 0; };
람다식
([인수명]) => [동작 or Return 값]
(number) => number%2 == 0;
선택 매개변수
정의에서 {}로 감싼 매개변수는 선택적으로 사용 가능. Named parameter.
void f(String name, {int age}) {}
{}로 감싸지 않은 매개변수를 필수적으로 넘겨주어야 하고, {}로 감싼 매개변수에 값을 주고 싶다면 반드시 매개변수의 이름을 붙여서 age : 5로 넘겨주어야 한다.
선택 매개변수는 기본값 지정이 가능하다.
void f(String name, {int age = 5}) {}
분기와 반복
if else
int a = 10; if (a % 2 == 0) {~} else if (a % 3 == 0) {~} else {~}
삼항 연산
[조건] ? [참일 때] : [거짓일 때]
var number = a%2 ? a++ : a--
switch case
조건에 맞는 값이 여러 개일 때 유용. enum과 함께 사용할 땐 모든 케이스를 검사해야 하는 강제성이 생김.
Switch - case - break로 문법은 C와 동일
for
요소를 반복.
for (var i = 0; i < 10 ; i++){ print(i); }
객체 지향 프로그래밍
dart는 객체지향 프로그래밍 언어!
클래스
객체 object : 저장 공간에 할당되어 값을 가지거나 식별자에 의해 참조되는 공간. (변수, 함수, 메서드)
인스턴스 instance : 객체를 메모리에 작성하는 것.
클래스 class : 인스턴스의 설계도.
속성 property : 클래스 안에 표현되는 속성.
클래스는 일종의 사용자 정의 타입!
class Person{ String name; int age; } var person = new Person(); var person2 = Person(); //new 생략 가능
변수명 뒤에 . 연산자를 입력, 객체의 property에 접근 가능.
print(person.name); print(person.age);
메서드 : 클래스 안에 작성하는 함수. 메서드는 class의 프로퍼티를 조작하는 등의 용도로 사용. 이 역시 .연산자를 붙여 접근 가능.
접근 지정자
java에서의 public, private와 같은 역할. 여기서는 _ 을 붙여 구분한다. (붙이면 private)
class Person{ String name; int _age; void addOneYear(){ _age++; } } //=====다른 Dart file import 'person.dart'; void main(){ var person = Person(); person._age = 10; //error! }
이때, private의 영역은 정의된 파일 내! 즉, _이 붙어 있어도 같은 파일 내라면 class의 밖에 있어도 자유롭게 접근이 가능하다.
생성자
인스턴스화 하는 방법을 제공하는 일종의 메서드. 인스턴스가 생성될 때 가장 먼저 생성됨. 메서드 이름은 클래스명과 같다.
class Person{ String name; int _age; Person({this.name, this._age}); //constructor } var person = Person(); var person2 = Person(name : '홍길동', _age : 20);
getter, setter
_을 붙인 private 변수에 외부에서 접근하기 위해 만들어주는 통로같은 메서드.
//person.dart class Person{ String name; int _age = 10; int get age => _age; //getter set setAge(num value) => _age = value; //setter } //main.dart void main(){ var person = Person(); print(person.age); //10 person.setAge = 5; print(person.age); //5 }
상속
implement. 주는 쪽이 super class (부모), 받는 쪽이 sub class(자식)
//부모 class class Hero{ String name = 'hero'; void run() {} } //위를 상속받은 자식 클래스 class SuperHero extend Hero{ @override //재정의 void run(){ super.run(); //부모의 run실행 this.fly(); //추가로 자식이 따로 정의한 fly도 실행. } void fly() {} } void main(){ var hero = SuperHero(); hero.run(); hero.fly(); print(hero.name); //hero 출력 }
추상 클래스
abstract class. 추상 메서드를 포함하는 클래스.
추상 메서드 : 선언만되고 정의가 없는 메서드.
추상 클래스는 다른 클래스에서 implement해서 완성하는 상속 재료로 사용된다. (틀같은 느낌? 템플릿?)
이때 대상 클래스에는 implements, 메서드에는 @override 키워드 사용(
여러 추상 클래스를 한번에 implement할 수도 있고, 추상 클래스를 구현할 때는 모든 추상 메서드를 재정의 해야 한다.
abstract class Monster{ void attack(); } abstract class Flyable{ void fly(); } class Bat implements Monster, Flyable( @override void attack(){ print('할퀴기!'); } @override void fly(){ print('펄럭펄럭'); } }
믹스인
mixin. with를 사용하면 상속하지 않고 다른 클래스 기능 overwritte가능.
class Goblin implements Monster{ @override void attack(){ print('고블린 공격'); } } class DarkGoblin extends Goblin with Hero{ } //다크 고블린은 고블린이기도 하며, 히어로이기도 하며, 몬스터이기도 함. => 다형성!
열거형
enum type. 상수를 정의하는 특수한 형태의 클래스. 상수처럼 사용이 가능하다.
enum Status { login, logout } var authStatus = Status.logout; switch(authStatus){ case Status.login: print('login'); break; case Status.logout: print('logout'); break; }
컬렉션
list, map, set등의 collection을 기본 제공함.
List
순서가 있는 자료를 담음. Dart는 배열 (Array)를 별도로 제공하지 않는다.
List<String> items = ['a', 'b', 'c']; var items = ['a', 'b', 'c']; items[0] = 'd'; //0부터 시작하는 index. print(items.length); //3
※ dynamic
모든 타입을 대변하는 특수 타입! 여러 타입을 한 리스트에 넣거나 일반 변수를 선언할 때도 사용 가능.
List<dynamic> list = [1, 2, 'a'];
var list = [1, 2, 'a'];
스프레드 연산자
spread. '...' 연산자. 컬렉션을 펼쳐준다. 다른 컬렉션 안에 컬렉션을 삽입할 때 사용.
var items = ['a', 'b', 'c']; var items2 = ['d', ...items, 'e']; //d, a, b, c, e
Map
순서 없음. 탐색 빠른 자료구조. key-value의 쌍.
//Map<String, String> cityMap = {...} 과 같음. var cityMap = { 'korea': 'busan', 'japan': 'tokyo', 'china': 'Beijing' }; cityMap['korea'] = 'seoul'; print(cityMap.length); //3 cityMap['America'] = 'Washington'; //새 값 추가
Set
집합 표현. => 중복 불허용
add(), remove()로 추가/삭제 가능.
contains() : 찾는 자료가 집합에 있는지 없는지 bool로 반환.
// Set<String> citySet = {}과 같음 var citySet = {'서울', '부산', '광주', '대전', '울산'} citySet.add('대구'); citySet.remove('서울'); print(citySet.contatins('울산'); // true
비어있는 Set이나 map을 작성할 때는 주의! 그냥 {}만 쓰면 Map으로 인식해버림.
var mySet = <String>{}; //set으로 인식 var mySet2 = {}; //dynamic, dynamic인 map으로 인식
함수형 프로그래밍
Dart는 객체지향 프로그래밍과 함수형 프로그래밍의 특징을 모두 제공 (뭐지....)
함수형 프로그래밍 : 자료 처리를 수학적 하수의 계산으로 취급하는 패러다임. (상태와 가변 데이터 X)
일급 객체
함수를 값으로 취급. 즉, 다른 변수에 함수를 대입할 수 있음.
void greeting(String text){ print(text); } void main(){ // 함수를 다른 변수에 대입할 수 있음 var f = greeting; f('hello'); }
다른 함수의 인수로 함수 자체를 전달하거나 함수를 반환받을 수도 있음.
함수를 매개변수로 전달, 수정, 변수에 대입하기가 가능한 객체를 '일급 객체', first-class object라고 함.
for문과 forEach()함수
for : 외부 반복
forEach() : 내부반복 =>(E element) {} 형태의 함수를 인수로 받음.
items.forEach(print); // 1, 2, 3, 4, 5 items.forEach((e) { print(e); }); itmes.forEach((e) => print(e)); items.forEach(print);
where
조건을 필터링 할 때 사용. 함수형 프로그래밍을 지원하는 함수들은 결과를 반복 가능한 타입으로 반환하여 메서드 체인으로 연결해서 사용 가능.
items.where((e) => e % 2 == 0).forEach(print); //2, 4
map
반복되는 값을 다른 형태로 변환하는 방법을 제공.
items.where((e) => e % 2 == 0).map((e) => '숫자 $e').forEach(print);
toList
함수형 프로그래밍을 지원하는 함수 대부분은 Iterable<T> 인터페이스 타입 인스턴스를 반환.
하지만 실제 사용할 때는 대부분 리스트 형태로 변환해야 하는 경우가 많음. => 결과를 리스트로 바꿔야함.
final result = itmes.where((e) => e % 2 == 0).toList();
toSet
리스트에 중복된 데이터가 있을 경우, 중복을 제거한 리스트를 얻고 싶을 때 집합인 set을 사용.
final result = itmes.where((e) => e % 2 == 0).toSet().toList();
any
리스트에 특정 조건을 충족하는 요소가 있는지 없는지 검사할 때 사용하는 함수.
print(items.any((e) => e % 2 == 0));
reduce
반복 요소를 줄여가면서 결과를 만들 때 사용하는 함수.
// 최댓값을 구할 때, 순차적으로 비교하는 로직 final result = items.reduce(max); //5
기타
계단식 표기법 .. 연산자
cascade notation .. 연산자. 동일 객체에서 일련의 작업을 수행 가능.
.. 연산자를 사용하면 메서드를 수행한 객체의 참조를 반환.
print(items ..add(6) ..remove(2)); //1, 3, 4, 5, 6
컬렉션 if
조건에 의해 컬렉션의 값을 조정하거나 다르게 사용하고 싶을 때 사용.
bool promoActive = true; print([1, 2, 3, 4, 5, if (promoActive) 6]); // true일 때만 6이 추가됨
컬렉션 for
컬렉션 문법 안에서 for 문을 사용 가능.
var listOfInts = [1, 2, 3]; var listOfStrings = [ '#0', for (var i in listOfInts) '#$i' ]; //#0, #1, #2, #3
null 처리
다트는 null을 처리할 수 있는 여러가지 방법을 제공. (Dart에서는 모든 것이 객체. int, double, bool 같은 타입들도 모두 객체라 null값을 가질 수도 있음.)
?. 연산자를 사용하면 null 여부 파악 가능.
print(name?.lentgh); //null출력
??연산자는 객체가 null일 때 작동을 간단히 구현하는데 사용.
print(name?.length ?? 0); //name이 null이면 0을 출력