환경 설정
- http 프로토콜을 사용하려면 AndroidManifest.xml과 info.plist파일을 설정해야 함
map
List<String> test = ['a', 'aa', 'b', 'bbb'];
final new_test = test.map((items) => 'test : $items');
print(new_test);
// (test : a, test : aa, test : b, test : bbb)
reduce
List<String> test = ['a', 'aa', 'b', 'bbb'];
final new_test = test.reduce((value, element) => value + ',' + element);
print(new_test);
// a,aa,b,bbb
fold
void main() {
List<String> test = ['a', 'aa', 'b', 'bbb'];
final new_test = test.fold<int>(0, (value, element)=> value + element.length);
print(new_test);
// 7
}
?
- double? number = 1;
⇒ 타입뒤에 ? 를 추가해줘야 null값이 저장될 수 있음
- double?? number = 1;
⇒ null값일때만 값 저장
익명함수와 람다함수
// 익명함수
void main(){
List<int> number = [3,4,6,2,7];
final allNumbwer = number.reduce((value, element) {
return value+element;
});
print(allNumbwer);
}
// 람다함수
List<int> number = [3,4,6,2,7];
final allnumber = number.reduce((value, element) => value+element);
print(allnumber);
typedef
typedef Operation = void Function(int x, int y);
void add(int x, int y){
print(x+y);
}
void subtract(int x, int y){
print(x-y);
}
void main(){
Operation operA = add;
Operation operS = subtract;
operA(5,7); //12
operS(5,6); // -1
}
class
class Idol{
final String name ;
//constructor 생성자
// Idol(String name) : this.name = name;
Idol(this.name);
void sayname (){
print('i\'m ${this.name}');
print('나는 $name 이다');
}
}
void main(){
Idol testIdol = Idol('eungyeong');
testIdol.sayname();
}
class Idol{
final String name ;
final int memberCount;
//constructor 생성자
Idol(String name, int memberCount):
this.name = name,
this.memberCount = memberCount;
// named constructor
Idol.fromMap(Map<String, dynamic> map)
: this.name = map['name'],
this.memberCount = map['memberCount'];
void sayname (){
print('i\'m ${this.name}');
print('나는 $memberCount 이다');
}
}
void main(){
// use constructor
Idol testIdol = Idol('eungyeong', 29);
testIdol.sayname();
// use named constructor
Idol bts = Idol.fromMap({
'name' : 'bts',
'memberCount' : 1,
});
bts.sayname();
}
private variable
class Idol{
String _name;
Idol(this._name);
}
getter, setter
class Idol{
String _name = 'test';
// 게터는 값을 가져올때 사용
String get name {
return this._name;
}
// 세터는 값을 지정할 때 사용
set name(String name){
this._name = name;
}
}
void main(){
// use constructor
Idol testIdol = Idol();
testIdol.name = 'test_name';
print(testIdol.name);
}
class & extends (상속)
- 공유되는 기능을 이어받는 개념
class Idol{
final String name;
final int memberCount;
Idol(this.name, this.memberCount);
void sayName(){
print('저는 ${this.name} 입니다.');
}
void saymemberCount(){
print('저는 ${this.memberCount} 입니다.');
}
}
class boyGroup extends Idol{
//상속받은 생성자
boyGroup(
String name,
int memberCount,
): super( // super는 부모클래스 지칭
name,
memberCount
);
void sayMale(){
print('남성아이돌');
}
}
void main(){
boyGroup bts = boyGroup('boyname', 12);
bts.sayName();
bts.saymemberCount();
bts.sayMale();
}
override
class Idol{
final String name;
final int memberCount;
Idol(this.name, this.memberCount);
void sayName(){
print('저는 ${this.name} 입니다.');
}
void saymemberCount(){
print('저는 ${this.memberCount} 입니다.');
}
}
class boyGroup extends Idol{
//상속받은 생성자
boyGroup(
String name,
int memberCount,
): super( // super는 부모클래스 지칭
name,
memberCount
);
void sayMale(){
print('남성아이돌');
}
}
class girlGroup extends Idol{
girlGroup(
super.name,
super.memberCount,
);
// 부모 클래스 또는 인터페이스에 정의된 메서드를 재정의할때 사용
@override
void sayName(){
print('저는 여자아이돌 ${this.name} 임니다.');
}
}
void main(){
boyGroup bts = boyGroup('boyname', 12);
bts.sayName();
bts.saymemberCount();
bts.sayMale();
girlGroup girl1 = girlGroup('girl name', 1234);
girl1.sayName();
}
인터페이스 (implements)
- 공통으로 필요한 기능을 정의만 해놓음
- 여러개 사용 가능
상속과 인터페이스 차이
- 상속받을때는 부모 클래스의 모든걸 물려받기 때문에 재정의 필요 없음
- 인터페이스는 반드시 모든기능을 재정의 해야함
믹스인(mixin)
- 특정 클래스에 원하는 기능만 골라 넣을 수 있는 기능
- 특정 클래스를 지정해서 속성들을 정의할 수 있음
- 지정한 클래스를 상속하는 클래스에서도 사용 가능
- 한번에 여러개 믹스인 사용 가능
class Idol{
final String name;
final int memberCount;
Idol(this.name, this.memberCount);
void sayName(){
print('저는 ${this.name} 입니다.');
}
void saymemberCount(){
print('저는 ${this.memberCount} 입니다.');
}
}
mixin IdolSingMixin on Idol{
void sing(){
print('${this.name}이 노래를 부름');
}
}
//믹스인을 적용할때는 with 키워드 사용
class boyGroup extends Idol with IdolSingMixin{
boyGroup(
super.name,
super.memberCount,
);
void sayMale(){
print('나는 남자아이돌이다.');
}
}
void main(){
boyGroup bts = boyGroup('boyname', 12);
bts.sing(); //boyname이 노래를 부름
}
추상(abstract)
- 상속이나 인터페이스로 사용하는데 필요한 속성만 정의하고 인스턴스화 할 수 없도록 하는 기능
abstract class Idol {
final String name;
final int membersCount;
Idol(this.name, this.membersCount);
void sayName();
void sayMembersCount();
}
class girlGroup implements Idol{
final String name;
final int membersCount;
girlGroup(this.name, this.membersCount);
void sayName(){
print('say my name : ${this.name}');
}
void sayMembersCount(){
print('member count : ${this.membersCount} ');
}
}
void main(){
girlGroup test_girl = girlGroup('test_girl', 34256);
test_girl.sayName();
test_girl.sayMembersCount();
}
제네릭 (generic)
- 클래스나 함수의 정의를 선언할 때가 아니라 인스턴스화 하거나 실행할때로 미룸
- 특정 변수의 타입을 하나의 타입으로 제한하고 싶지 않을때 자주 사용함
class Cache<T>{
final T data;
Cache({
required this.data,
});
}
void main(){
final cache = Cache<List<int>>(
data:[1,2,3],
);
print(cache.data.reduce((value, element) => value+element));
}
스태틱 (static)
- static을 사용하면 클래스 자체에 값이 귀속됨
class Counter {
static int i=0;
Counter(){
i++;
print(i);
}
}
void main(){
Counter c1 = Counter(); // 1
Counter c2 = Counter(); // 2
Counter c3 = Counter(); // 3
}
캐스케이드 연산자
class Idol{
final String name;
final int memberCount;
Idol(this.name, this.memberCount);
void sayName(){
print('저는 ${this.name} 입니다.');
}
void saymemberCount(){
print('저는 ${this.memberCount} 입니다.');
}
}
mixin IdolSingMixin on Idol{
void sing(){
print('${this.name}이 노래를 부름');
}
}
//믹스인을 적용할때는 with 키워드 사용
class boyGroup extends Idol with IdolSingMixin{
boyGroup(
super.name,
super.memberCount,
);
void sayMale(){
print('나는 남자아이돌이다.');
}
}
void main(){
boyGroup bts = boyGroup('boyname', 12)
..sayName() //요기
..saymemberCount();
}
Future
- 비동기 프로그래밍 테스트
- 반환값을 딱 한번 받아내는 비동기 프로그래밍에 사용함.
- 지속적으로 값을 반환받을때는 stream 사용
void main(){
addNumber(1,1);
}
void addNumber(int num1, int num2){
print('$num1 + $num2 = ${num1+num2} 시작!');
Future.delayed(Duration(seconds: 3), (){
print('$num1 + $num2 = ${num1+num2}');
});
print('$num1 + $num2 코드 실행 끝!');
}
//출력
// 1 + 1 = 2 시작!
// 1 + 1 코드 실행 끝!
// 1 + 1 = 2
async & await
- 코드가 작성된 순서대로 실행
void main(){
addNumber(1,1);
}
Future<void> addNumber(int num1, int num2) async {
print('$num1 + $num2 start');
await Future.delayed(Duration(seconds: 3),(){
print('$num1 + $num2 = ${num1+num2} here!');
});
print('$num1 + $num2 end');
}
stream
- 지속적으로 값을 반환 받을때
import 'dart:async';
void main(){
final controller = StreamController();
final stream = controller.stream;
// callback function when value is add
final streamListener1 = stream.listen((event) {
print(event);
});
// add value into stream
controller.sink.add(1);
controller.sink.add(2);
controller.sink.add(3);
controller.sink.add(4);
controller.sink.add(5);
}
broadcast stream
- 브로드캐스트 스트림
import 'dart:async';
void main(){
final controller = StreamController();
// multiple listen
final stream = controller.stream.asBroadcastStream();
// first
final streamListener1 = stream.listen((event) {
print('first + $event');
});
// sencond
final streamListener2 = stream.listen((event) {
print('second $event');
});
// add value into stream
controller.sink.add(1);
controller.sink.add(2);
controller.sink.add(3);
}
함수로 스트림 반환하기
import 'dart:async';
// stream을 반환하는 함수는 *async*으로 선언
Stream<String> calculate(int num) async*{
for (int i=0; i<5; i++){
// streamController의 add()처럼 yield키워드를 이용하여 값 반환
yield 'i = $i';
await Future.delayed(Duration(seconds: 1));
}
}
void playStream(){
// streamController와 마찬가지로 listen()함수로 콜백 함수 입력
calculate(1).listen((event) {
print(event);
});
}
void main(){
playStream();
}
recode
void main(){
(String, int, bool) test = ('test', 20, true);
print(test.$1);
print(test.$2);
print(test.$3);
({String name, int age}) test2 = (age:23, name:'이름');
print(test2.name);
print(test2.age);
}
destructuring
void main(){
// final test = ['테스트1', '테스트2'];
// final t1 = test[0];
// final t2 = test[1];
final [test1, test2] = ['테스트1', '테스트2'];
print(test1);
print(test2);
}
void main(){
final numbers = [1,2,3,4,5,6,7,8,9,10];
final [x,y, ..., z] = numbers;
print(x); // 1
print(y); // 2
print(z); // 10
}
void main(){
final testMap = {'name1':'이름', 'age2':10};
final {'name1' : name, 'age2' : age} = testMap;
print('name : $name');
print('age : $age');
}
switch
void main(){
String dayKo = '월요일';
String dayEng = switch(dayKo){
'월요일' => 'Mon',
'화요일' => 'Tue',
'수요일' => 'Wen',
'목요일' => 'Thur',
'금요일' => 'Fri',
'토요일' => 'Sat',
'일요일' => 'Sun',
_ => 'Not Found',
};
print(dayEng);
}
패턴 매칭 (pattern matching)
void swticher(dynamic anyting){
switch(anyting){
// 정확히 'aaa'문자열만 매치
case 'aaa':
print('match : aaa');
break;
// 정확히 [1,2] 리스트만 매치
case [1,2]:
print('match : [1,2]');
break;
// 3개의 값이 들어있는 리스트 모두 매치
case [_,_,_]:
print('match : [_,_,_]');
break;
// 첫번째와 두번쨰 값에 int가 입력된 리스트를 매치
case [int a, int b]:
print('match : [int $a, int $b]');
break;
// 첫번째값에 String, 두번째 값에 int가 입력된 recode 타입을 매치
case (String a, int b):
print('match ; [String $a, int :$b ]');
break;
default:
print('no match');
}
}
void main(){
swticher('aaa');
swticher([1,2]);
swticher([1,1,2,2]); // no macth
swticher([3,4,5]);
swticher([2,4]);
swticher(('test', 33));
swticher(8); // no macth
}
엄격한 검사(exhaustiveness checking)
- 코드가 입력 받을 수 있는 모든 조건 확인
void main(){
bool? val;
switch(val) {
case true:
print('true');
case false:
print('false');
default :
print('null');
};
}
보호구문 (guard clause)
- when 키워드로 보호구문 추가 가능
- boolean으로 반환할 조건을 각 case문에 추가 가능
void main(){
(int a, int b) val = (1, -1);
switch(val){
case (1,_) when val.$2 > 0:
print('1, _');
break;
default:
print('default');
}
}
클래스 제한자
- 모든 클래스 제한자는 class키워드 앞에 명시해야 함.
base
- base의 기능을 강제하는 제한자
- 해당 클래스는 오직 상속만 가능
base class Parent{}
// 인스턴스 화 가능
Parent parent = Parent();
// 가능
base class Child extends Parent{}
// subtype of base of final is not base fianl or sealed 에러 발생
// base / sealed / final 제한자 중 하나 필요
// class Child2 extends Parent{}
// subtype of base of final is not base fianl or sealed 에러 발생
// base 클래스는 implement 불가능
// class Child3 implements Parent{}
final
- 같은 파일에서는 상속(extends)와 재정의(implements)할수 있지만, 외부 파일에서는 할수 없음
- final 제한자는 base 제한자의 기능을 모두 포함함
// filename => a.dart
final class Parent{}
import 'a.dart';
// 인스턴스화 가능
Parent parent = Parent();
// extends 불가능
class child extends Parent{]
//implement 불가능
class child2 implements Parent{}
interface
- 클래스를 외부 파일에서 상속받지 못하고 재정의만 할수 있도록 제한하는 역할
interface class Parent{}
import 'a.dart';
// 인스턴스화 가능
Parent parent = Parent();
// extends 불가능
class child1 extends Parent{}
// implement 가능
class child2 implements Parent{}
sealed
- sealed클래스를 파일 외부에서 상속, 재정의 그리고 인스턴스화 할 수 없도록 제한
sealed class Parent{}
import 'a.dart'
// 인스턴스화 불가능
Parent parent = Parent();
// extends 불가능
class child1 extends Parent{}
//implement 불가능
class child2 implements Parent{}
mixin
- 일반 mixin과 같은 역할을 하면서도 상속할수 있다는 장점이 있음
mixin class MixinExample{}
// extend 가능
class child1 extends MixinExample{}
//mixin 으로 사용 가능
class child2 with MixinExample{}