EunGyeongKim

플러터 문법 정리 본문

기타 공부

플러터 문법 정리

EunGyeongKim 2024. 4. 11. 21:23

환경 설정

  • 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{}

  • 클래스 제한자 조합시 허가되는 기능

Comments