dart 언어

https://dartpad.dev/

일반

void main() {
  for (int i = 0; i < 5; i++) {
    print('hello ${i + 1}');
  }
  
  // type
  String, double, int, bool, var
    
  print ( name + ' ' + name2);
  print ('$name $name2');  // 변수만 쓰면 {} 없어도 됨
  print ('${number+1} ${name2}');
  
  // var, dynamic
  print (name.runtimeType);
  //var : 한번 선언하면 fix
  // dynamic : type 바뀔 수 있음
  
  // nullable, non-nullable
  String? name = 'asd';  // ? 끝에 붙이면
  name = null;   //가능
  print(name2!); // !현재 이값은 null이 아니다 (null 안들어가는 함수쓸 때)
  
  final String name = 'asdf';  // name 바꿀 수 없음
  const String name2 = 'asdf'; // 비슷
  final name = 'sdaf'; // type 생략 가능
  const name2 = 'sadf';  // type 생략 가능
  // 차이 
  // final : build time 
  final DateTime now = DateTime.now();  //build time 몰라도 됨
  // const 는 안됨 : build time 알고 있어야 함 (절대적으로)

  // % : 나머지
  number ++;  // +1 하면서 변경   ex. --; 
  number += 2;  // +2 하면서 변경   ex. *=, /=
  
  number ??= 3;  // number가 null이면 3 (아니면 안바뀜)

  // == 같은지, != 다른지

  // type비교
  print (number1 is int);
  print (number1 is! String);
  
  bool result = 12 > 10 && 1 > 0;	// || : or

  // List
  List<String> lst = ['1','2','3'];	// List<int> numbers = [1,2,3];
  lst[0];		lst.length;	 lst.add('4');	 lst.remove('3');	 lst.indexOf('4');
  
  // Map : Key/Value
  Map<String, String> dictionary = { 'a' : '1', 'b' : '2', };
  dictionary.addAll( { ~~~ } );
  dictionary['a'];
  dictionary['c'] = '3';	dictionary['c'] = '4';	//변경
  dictionary.remove('a');	dictionary.keys;	dictionary.values;

  // Set : 중복없는 list
  final Set<string> names = { 'a','b','c', 'c' };
  names.add('d');	names.remove('a'); 
  names.contains('d');
  
  if (조건) {  } else if ( 조건 ) { } else {  }

  switch ( number % 3 ) { 
   case 0:
     print('sadf');
     break;	//넣어줘야 함
   case 1:
     ...
   default:
     print('sdf');
     break;
  }

  for ( int i = 0; i < 10; i++) { }
  for ( int number in numbers ) { } // numbers list에 있는 값들

  while ( 조건 ) {  }
  do { } while ( );		//먼저 do 하고 (거의 안씀)

  // break; 	// continue;

}





// enum : 함수 밖에 선언
enum Status { approved, pending, rejected, }  // 함수 밖에 선언
//사용할 때
Status status = Status.pending;
if (status == Status.approved ) { .... }
// 정확히 이 세개 밖에 없다는 것을 알려줌, 오타 방지


///////////////////////////////////////////////////////////////////////////////////////
//// 함수
///////////////////////////////////////////////////////////////////////////////////////
// positional parameter
addNumbers(int x, [int y=20, int z=30]) {  }	// [ Optional ], null이 된다면 [int? y, int? z]	// 없으면 void와 동일
// named parameter
addNumbers({ required int x, required int y, required int z } ) {  } 	// addNumbers(y:10, x:20, z:30 )	// 순서 바뀌고 이름 넣어야 함
addNumbers({ required int x, required int y, int z=30 } ) {  } 	// required 없애면 optional이 됨 
int addNumbers ( ) { return x; }
// arrow function
int addNumbers( int x, {required int y, int z = 30,} ) => x+y+z;

// typedef : 함수 밖에 선언 
typedef Operation = int Function(int x, int y, int z);	//
int add(int x, int y, int z) => x+y+z;
int substract(int x, int y, int z) => x-y-z;
// 사용할 때1
Operation operation = add;	// add라는 함수로 정의
int result = operation(10,20,30);
// 사용할 때2
int calculate(int x, int y, int z, Operation operation) {
 return operation(x,y,z);
}}
int result2 = calculate(30,40,50,add);
  
  




///////////////////////////////////////////////////////////////////////////////////////
//// CLASS
///////////////////////////////////////////////////////////////////////////////////////
void main() {
  //Idol blackpink = Idol();	// new Idol(); 같음
  //Idol blackpink = Idol('블랙핑크', ['a','b','c']);	// new Idol(); 같음
  print(blackpink.name);
  blackpink.sayhello();
}

// Idol class
class Idol {	// _Idol (constructor 이름도 바꿔주면) : private 속성 : 다른파일에서 import 해도 못씀
	
  final String name;
  final List<String> members;	// 웬만하면 final 로 선언해야 함 : immutable programming

  // CONSTRUCTOR 사용법
  // 1. constructor
  Idol(String name, List<String> members)
   : this.name = name;	
     this.members = members;
  // 2. 
  // Idol(this.name, this.members); //로 하면 더 간단함
  //    const Idol(this.name, this.members); 로 하면 좋음?	//const constructor : (변수들이 final일 때)
  //      -> 사용할 때 Idol blackpink = const Idol('A', ['a'] );
  //      Idol blankpink2 = const Idol('A', ['a'] );  // 일 때,(똑같은 변수) const 이면 blackpink == blankpink2 는 true, 아니면 false
  // 3. named constructor
  Idol.fromList(List values)
   : this.members = values[0],
     this.name = values[1];
  // 1or2 와 공존 가능하고,
  // instance 선언할 때
  // Idol bts = Idol.fromList ( [ ['a','b','c'], 'BTS' ] );  // 로 사용 가능


  void sayHello() {
    print('안녕하세요 ${this.name} 입니다.');		// method 안에 name 없으면 this. 없어도 됨
  }
  void introduce() {
    print('저희 멤버는 ${this.members}가 있습니다');
  }
  
  // getter
  String get firstMember {	// () 없음
	return this.members[0];
  }  // 사용 : blackpink.firstMember
  
  // setter
  set firstMember(String name) {	//무조건 한개 parameter
	this.members[0] = name;		
  }		// final, const 없어야 함
  // 사용 : blackpink.firstMember = '아이언맨'
  // final (immutable programming) 때문에 setter는 잘 안씀
  
  
  
  //static은 instance에 귀속되지 않고, class에 귀속된다
  static String? building;	// Idol.building = '하이브타워';	// 클래스에 direct로, instance끼리 공통
  static void printBuilding() { }	// static method
  
  
}


// 상속 (inheritace)
// BoyGroup은 Idol type 도 됨 : is Idol = true
class BoyGroup extends Idol {	//extends
	BoyGroup ( String name, int membersCount, ) :
		super(name : name, membersCount : membersCount);	//constructor : super 
	
	void sayMale() {
		print("나는 남자");
	}
	
	// method - class 내부에 있는 함수
	// override
	
	@override	// @override 써주면 직관적임 (없어도 됨)
	void method_of_parent() {
		return super.method_of_parent() ~~~;		//super 부모 method 그대로 가져오기
	}
	
	
}

// interface : 클래스에 필수적인 template
abstract class Idolinterface() {	
//abstract : instance로 만들 수 없음 (설계로만 쓸거임)
	String name;
	IdolInterface(this.name);
	void sayName() {}
}
class BoyGorup implements Idolinterface{
	//인터페이스와 동일한 구조로 만들어야 함
}


// generic : 타입을 변수처럼 외부에서 받을 때
// ex. List<String> : List를 String으로
class Lecture<T> {	// <T,X> 여러개 넣을 수 있음
	final T id;
	final String name;	
	
	Lecture(this.id, this.name);
}
// Lecture<String> lec1 = Lecture('123','lec1');


// OOP : 모든 클래스는 extends Objects() 하고 있음




///////////////////////////////////////////////////////////////////////
//Functional Programming : (중요 : 새로운 객체로 나옴!)
///////////////////////////////////////////////////////////////////////
// 코드 간결

// 형변환
List<String> b = ['a',...,'d'];
b.asMap();
b.toSet();

Map c = b.asMap();
c.keys;	// () : Iterable<> -> List로 바꿔줘야 함
c.keys.toList();

// map : 새로운 list가 나옴 ( b == new_b : false )
final new_b = b.map((x) {	// list의 각각 원소가 x로 들어감
				return '블랙핑크 $x';	
			} );
new_b.toList(); 	//Iterable 로 나오니까

//arrow 로 간편하게
final new_b2 = b.map( (x) => '블랙핑크 $x' );				

// map 예시
String number = '13579';
final parsed = number.split('').map( (x) => '$x.jpg').toList();	// [1.jpg, 2.jpg, ...]


//MAP 형인 경우
final result = new_b.map( (key,value) => MapEntry( 'asdf $key', '123 $value',) );
final keys = new_b.keys.map( (x) => 'sdf $x').toList();

//Set형 인경우
newSet = b.map( (x) => ... ).toSet();


// Where
List< Map<String, String> > people = [ {'name': ~~, 'group': '~~~'}, {~~~} ];		// List 안에 Map
final blackpink_p = people.where( (x) => x['group'] == '블랙핑크' ).toList();	//맞는것만 남김

//Reduce
List <int> numbers = [1,3,5,7,9];
final result = numbers.reduce( (prev,next) {
	print('----');
	print('prev : $prev');
	print('next : $next');
	
	return prev+next;
} );
//(1+3) -> 4 // + 5 -> 9 // + 7 = 16...
final result = numbers.reduce( (prev,next) => prev + next );


List<String> words = ['a','b','c'];
final sentence = words.reduce( (prev,next) => prev + next );	

//Fold : return이 같은 형이 아니어도 됨
final sum = numbers.fold<int>( 0, (prev,next) => prev + next );	// 0 + 1 = 1 // + 3
final sentence = words.fold<String>( '', (prev,next) => prev + next );	
final count = words.fold<int>( 0, (prev,next) => prev + next.length );	//글자들의 길이

// cascading operator
List<int> even = [2,4,6,8];
List<int> odd = [1,3,5,7];
print( [...even, ...odd]);	// ... 하면 List 없어지고, 원소들이 나옴  (원래는 [[...], [...]] )



// 예시
// 원래 Map은 name, group 말고 다른 이름이든 다른 추가 내용이든 있을 수 있음 (자유도 높음)
// Json 등으로 들어온 데이터를 class 로 유효성 검사?
List< Map<String, String> > people = [ {'name': ~~, 'group': '~~~'}, {~~~} ];		// List 안에 Map

final parsedPeople = people.map ( (x) => Person ( name: x['name']!, group: x['group']!, ) ).toList();	// !로 무조건 존재한다 표현
print(parsedPeople);	// toString override한 걸로 string 으로 바뀌어서 출력됨 (원래는 'instance of Person' 으로 출력됨 )

// 아래 처럼 data 유효성 검사 없이 활용 가능함
for (Person person in parsedPeople) {
	print(person.name);
	print(person.group);
}
final bts = parsedPeople.where( (x) => x.group == 'BTS');


class Person {
	final String name;
	final String group;
	
	Person( { 
		required this.name, required this.group, } );
		
	@override
	String toString() {
		return 'Person(name:$name, group:$group)';
	}
}






///////////////////////////////////////////////////////////////////////
////Asynchronous Programming
///////////////////////////////////////////////////////////////////////

// CPU Thread : 실행 단위 (실행 중에는 사용 불가)
// 서버요청 예시 : Network 요청을 위해서 돌아올 때까지 CPU가 막혀버림 (사용하지 않음에도) : synchronous programming
// CPU 효율적으로 사용하는 방법

//Future
//Future<String> name = Future.value('코드팩토리');	//미래에서 받아올 값

// delayed - 2개의 파라미터 : 지연할 기간 Duration, 지연 지난 후 실행할 함수
Future.delayed( Duration(seconds: 2), () { print('Delay 끝'); } );

//예시
void addNum(int n1, int n2) {
	print (' 시작 ' );	
	//서버시뮬레이션
	Future.delayed( Duration(seconds:2), () {
		print(' 계산완료');
	});
	print ('함수완료');
}

addNum(1,1);   //실행하면 : 시작->함수완료->계산완료	(Future 없으면 시작->계산완료->함수완료)
//CPU 쉬고 있는 순간 다른 것 먼저 실행


//await : 실제로 논리적으로 기다리긴 함
//함수완료에서 await 결과가 필요할 때
void addNum(int n1, int n2) async {		//async 필요함
	print (' 시작 ' );	
	//서버시뮬레이션
	await Future.delayed( Duration(seconds:2), () {		//await
		print(' 계산완료');
	});
	print ('함수완료');
}
//하지만 CPU는 다른 작업하기는 함
addNum(1,1);
addNum(2,2); 	// 계산시작(1,1) - 계산시작(2,2) - (계산완료 - 함수완료)(1,1) - (계산완료 - 함수완료)(2,2)


// 1,1  2,2 순서대로 하고 싶을 때
void main() async{
	await addNum(1,1);
	await addNum(2,2);
}
//await은 Futre가 return되는 것만 됨
Future<void> addNum(....) { }


// 받아서 사용
void main() async{
	Future result1 = await addNum(1,1);
	Future result2 = await addNum(2,2);
	
	print( result1+result2);
}


//Stream
// Futre : 실행 -(await)->완료-반환 (1개)
// Stream : 실행 -(yield-반환값1)-(yield-반환값2) -... -> 완료

import 'dart:async';	// 잘 안씀 : open src pkg 가 있으니까 이런 raw lib 쓸일은 없음

final controller = StreamController();
final stream = controller.stream.asBroadcastStream();	//as~ : 2번이상 listener하려면 필요


//1은 짝수만, 2는 홀수만
final streamListener1 = stream.where( (val) => val % 2 == 0).listen( (val) {
	print('Listener 1: $val');
	});
	
final streamListener2 = stream.where( (val) => val % 2 == 1).listen( (val) {
	print('Listener 2: $val');
	});	

controller.sink.add(1);
controller.sink.add(2);
controller.sink.add(3);
controller.sink.add(4);
controller.sink.add(5);


// 예시
void main(){
	
	// 1초씩 동시에 실행됨
	cal(2).listen( (val) {
		print (' $val');
	});
	
	cal(4).listen( (val) {
		print (' $val');
	});
}

Stream<int> cal(int num) async* {
	for (int i=0; i<5; i++ ) {
		//return i*num;	//return 이면 0만 return 되고 끝나버림
		yield i*num;	//cal 함수를 listening하는 stream에 값을 뿌려줄 수 있음
		
		
		await Future.delayed( Duration(seconds: 1));	// 1초씩 계산되어 나옴
	}
}


// 순서대로 실행
playAllStream.listen( (val) { print(val); });

Stream  <int> playAllStream() async* {
	yield* cal(1);		// * : 모든 값이 나올 때까지 기다림
	yield* cal(1000);
}

날짜, Duration

DateTime now = DateTime.now();

now
now.year
now.month
now.day
now.hour
now.minute
now.second
now.millisecond

Duration duration = Duration(seconds: 60);
duration
duration.inDays
duration.inHours
duration.inMinutes
duration.inSeconds
duration.inMilliseconds


DateTime sepcificDay = DateTime(
	2023,11,23,	//위 순서대로 
);

final diff = now.difference(specificDay);
diff.inDays // ....

now.isAfter(specificDay)
now.isBefore(specificDay)

now.add(Duration(hours:10))
now.substract(Duration(seconds:20))