Dart 공부

devkwon·2023년 1월 26일
0

Dart를 사용하는 이유

다트는 JIT(Just-In-Time)컴파일과 AOT(Ahead-Of-Time)컴파일을 모두 지원한다.

AOT 컴파일러는 다트 코드를 효율적인 네이티브 코드로 변환시킨다.
다트의 선택형 JIT 컴파일러는 핫 리로드를 지원한다. 따라서 빠른 개발 속도와 반복이 가능하다.

String Concatenate

void main(){
	var name = "Socrates";
    var group = "Human";
    print("$name is $group");
    print("${name + " = " + group}")
}

var 타입 vs dynamic 타입

var 타입은 변수 초기화(Initalize) 때 지정된 타입이 var 변수의 타입이 된다.
dynamic 타입은 변수 초기화와 무관하게 대입되는 모든 변수의 타입으로 변환이 가능하다.

void main() {
  var varVariable = 'test';
  varVariable = 1; // error
  
  dynamic dynamicVariable = 'test';
  dynamicVariable = 1;
}

다음과 같이 var 타입 변수에 아무런 값을 넣지 않으면 dynamic 타입으로 자동으로 변환된다.

void main() {
  var name; // dynamic;
}

List

c#과 동일하게 <>로 타입을 지정하여 리스트를 만들 수 있다. 타입이 없으면 dynamic으로 지정된다. 특이한 점은 중괄호가 아닌 대괄호로 묶는다.

void main() {
  List dynamicList = [ // dynamic list
    1,
    2,
    3
  ];
  
  List<int> intList =[
    1,
    2,
    3
  ];
}

Map

리스트와 마찬가지로 타입을 지정하지 않으면 dynamic 타입으로 지정된다.

void main() {
  Map dictionary = {
    'One' : 1,
    'Two' : 2
  };
  
  Map<String,int> dictionary2={
    'One' : 1,
    'Two' : 2
  };
  
  dictionary2.addAll({'Three' : 4});
  print(dictionary2);
  
  dictionary2['Three']=3;
  print(dictionary2);
  
  dictionary2.remove('Three');
  print(dictionary2);
}

{One: 1, Two: 2, Three: 4}
{One: 1, Two: 2, Three: 3}
{One: 1, Two: 2}

final vs const

final, const 모두 값을 한 번 지정하면 변경할 수 없다는 건 동일하나,
const는 빌드 타임에 값이 지정되어 있어야하지만, final은 런타임에 지정해도 상관없다.

void main() {
  final var1;
  final int var2 = 2;
  
  const var3;
  const int var4 =4;
  
  var1=1;
  var3=3; // error
}

Optional Parameter

optional parameter들은 값을 전달하지 않았을 경우 사용할 수 있는 디폴트 값을 지정할 수 있다. 만약 지정하지 않았다면 null이 된다.

Optional position parameter
위치를 기반으로 값을 전달한다. []로 표시한다.

Optional named parameter
이름을 기반으로 값을 전달한다. 따라서 파라미터의 위치는 중요하지 않다. {}로 표시한다. 위치 기반으로 값을 전달할 수 없다.

void optPosFunc(int num1, [int num2=0]){
  print('$num1, $num2');
}

void optNamedFunc(int num1, {int? num2}){
  print('$num1, $num2');
}

void main() {
  optPosFunc(1);
  optNamedFunc(num2:0, 1);
}

1, 0
1, 0

typedef

delegate와 비슷하게 함수를 변수처럼 사용할 수 있게 해준다.

typedef Operation(int x, int y);
void add(int x, int y){
  print(x+y);
}
  
void subtract(int x, int y){
  print(x-y);
}
  
void calculate(int x, int y, Operation oper){
  oper(x,y);
}
void main() {
  calculate(1,2,add);
  calculate(1,2,subtract);
}

3
-1

클래스 생성자

Named Constructor라고 클래스명.생성자명으로 생성자 오버로딩을 할 수 있다.

class Person{
  String _name; //private
  int age; // public
  Person(name,age):this._name = name, this.age=age;
  
  Person.fromMap(Map values) // Named Constructor
    :this._name=values['name'],
      this.age=values['age'];
  
   void PrtInfo(){
    print('$_name, $age');
  }
}
void main() {
  Person p1 = new Person('p1',11);
  Person p2 = new Person.fromMap({
    'name' : 'p2',
    'age' : 11
  });
  
  p1.PrtInfo();
  p2.PrtInfo();
}

p1, 11
p2, 11

인터페이스

다트에서는 인터페이스 키워드를 사용하지 않고 클래스를 인터페이스로 사용한다.

class PersonInterface{
  void PrtInfo(){}
}
class Person implements PersonInterface{
  String _name; //private
  int age; // public
  Person(name,age):this._name = name, this.age=age;
  
   void PrtInfo(){
    print('$_name, $age');
  }
}

Cascade Notation

이전에 사용한 객체에 대해 일련의 작업을 수행할 수 있어 임시변수의 사용을 줄일 수 있다. 메서드 외 필드에도 적용이 가능하다. 중첩도 가능하다. 리턴 값이 없는 void 메서드에는 사용이 불가능하다.

new Person('p2',11)
    ..PrtInfo(); 

Late

non-nullable한 변수의 초기화를 나중에 할 수 있다.

int func(){
  return 1;
}

void main() {
  late int a = func();
}

fold, reduce

fold

리스트에 대해 loop를 도는 메서드다. 인자로 시작할 인덱스, 이전 루프에서 리턴한 값, 현재 인덱스 값을 가진다.

void main() {
  List<int> numbers=[
    1,2,3,4,5
  ];
  
  int total = numbers.fold(0,(total,element){
    print('total: $total, element: $element');
   return total+element; 
  });
  
  print(total);
}

total: 0, element: 1
total: 1, element: 2
total: 3, element: 3
total: 6, element: 4
total: 10, element: 5
15

reduce

시작 인덱스를 받지 않고 무조건 인덱스 0번부터 시작하는 fold이다.

void main() {
  List<int> numbers=[
    1,2,3,4,5
  ];
  
  int total = numbers.reduce((total,element){
    print('total: $total, element: $element');
   return total+element; 
  });
  
  print(total);
}

total: 1, element: 2
total: 3, element: 3
total: 6, element: 4
total: 10, element: 5
15

reduce는 시작할 때 total 값이 첫 번째 인덱스 값이 들어간다. 따라서 해당 리스트의 타입만 이용할 수 있다.
예를 들어 String 리스트의 단어들의 길이를 다 더하는 루프를 만든다고 할 때, fold는 가능하지만 reduce는 첫 번째 값인 'test1'이 total에 들어가므로 에러가 난다. (string -> int 불가능)

void main() {
  List<String> numbers=[
    'test1',
    'test2',
  ];
  
  int total = numbers.fold(0,(total,element){
   return total+element.length; // string -> int
  });
  
  print(total);
  
   int total = numbers.reduce((total,element){ //이미 total에 string인 'test1'이 들어가 있음. 
   int로 변환 불가능.
   return total+element.length; // string -> int
  });
}

Arrow Function

람다식과 똑같은 역할을 한다.

void main() {
  List<String> numbers=[
    'test1',
    'test2',
  ];
  
  int total = numbers.fold(0,(total,element) =>total+element.length);
  
  print(total);
}

10

extends, implements, with

extends

슈퍼 클래스의 메서드를 구현 없이 사용할 때 사용됨. 다중 상속이 불가능함.

implements

슈퍼 클래스의 메서드를 필수적으로 구현해서 사용하도록 할 때 사용됨. 다중 상속이 가능함.

with

여러 클래스들의 메서드를 재사용하기 위해 사용됨.
상속처럼 보이지만 실제로는 하나의 슈퍼 클래스만 존재하기 때문에 상속이 아니다. 따라서 여러개의 클래스를 with로 받을 수 있다.

mixin

추상 클래스와 비슷한 개념으로 유사한 기능, 속성을 가진 다양한 클래스들의 메서드를 재사용할 수 있게 한다. mixin 클래스는 생성자가 없어야 한다.

mixin First {
  void firstFunc(){
    print('hello');
  }
}
 
mixin temp {
  void number(){
    print(10);
  }
}

mixin Third{
  void thirdFunc(){
    print('not override');
  }
}
 
// mixin type used with keyword
class Second with First,Third, temp{
  @override
  void firstFunc(){
    print('can override if needed');
  }
}
 
void main(){
  var second = Second();
  second.firstFunc();
  second.thirdFunc();
  second.number();
}

can override if needed
not override
10

0개의 댓글