Flutter : Dart

김가영·2021년 5월 9일
0

Flutter

목록 보기
2/5
post-thumbnail

다트의 모든 변수는 객체이다

dart에서 null을 다루는 법

sound null safety

sound null safety : null이라고 정의하지 않는한 null이 될 수 없음

그럼 어떻게 null이라고 정의해줄 수 있을까? -> ? 연산자를 이용한다

int? a = null;

? 연산자를 이용하여 nullable(null이 가능하도록)로 정의하면 initial value가 null이 된다.

null-aware operator

null일 수도 있는 값들을 다룰 때는 항상 주의해야한다.

??=

유용한 연산자 중 하나는 ??=

왼쪽 변수가 null이 아닐때에만 값을 할당한다.

예를 들어

a ??= 5

라는 식이 있을 때, a가 3일 때에는 a의 값이 변하지 않지만 a가 null이었다면 5로 바뀌게 된다.

??

왼쪽 expression의 값이 null이 아니면 왼쪽 값을, null이면 오른쪽 값을 return 한다.

print(1 ?? 3); // print(1);

print(null ?? 12); // print(12);

?.

myObject?.someProperty

null일지도 모르는 변수를 다루는 또다른 방법.

만약 myObject가 null 이 아니라면 someProperty에 접근하고, null이라면 null을 return 한다.

collections

Dart는 list, map, set을 literal로 지원한다.

final aListOfStrings = ['one', 'two', 'three'];
final aSetOfStrings = {'one', 'two', 'three'};
final aMapOfStringsToInts = {
  'one': 1,
  'two': 2,
  'three': 3,
};

또는,

final aListOfInts = <int>[];
final aSetOfInts = <int>{};
final aMapOfIntToDouble = <int, double>{};

Cascades

하나의 객체에 여러 작업을 하고 싶을 때가 있다.

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

이런식으로.

모든 작업은 button(querySelector('#confirm')) 에 대한 작업이기에 우리는 .. 이라는 새로운 연산자를 도입할 수 있다.

...을 통해 객체의 맴버변수(또는 함수)에 접근하는 것과 굉장히 유사하다.

예를 들어 우리는 someObject.someFunction() 처럼 . 을 이용하여 someObject의 함수에 접근할 수 있다. 차이점이 있다면 위 표현은 someFunction()의 return 값을 가질 것이다.

대신, someObject..someFunction()은 여전히 someObject의 someFunction을 작동시키지만 여전히 someObject의 참조값을 가진다.

그러므로 ..을 이용하여 아래의 식처럼 계속해서 연쇄적으로 querySelector에 접근할 수 있다.

querySelector('#confirm')
..text = 'Confirm'
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));

Getters and setters

class MyClass {
  int _aProperty = 0;

  int get aProperty => _aProperty;

  set aProperty(int value) {
    if (value >= 0) {
      _aProperty = value;
    }
  }
}

dart에서의 함수

parameter

dart의 함수는 두가지 형태의 parameter를 가진다 : positionalnamed

positional은 그냥 기본적인 형태의 parameter이다. 위치에 따라 구분한다.

int sumUpToFive(int a, [int? b, int? c, int? d, int? e]) {
  int sum = a;
  if (b != null) sum += b;
  if (c != null) sum += c;
  if (d != null) sum += d;
  if (e != null) sum += e;
  return sum;
}
// ···
  int total = sumUpToFive(1, 2);
  int otherTotal = sumUpToFive(1, 2, 3, 4, 5);

dart에서는 [] 대괄호를 이용하여 positional parameter들을 optional하게 만들 수 있다.

int sumUpToFive(int a, [int b = 2, int c = 3, int d = 4, int e = 5]) {
// ···
}
// ···
  int newTotal = sumUpToFive(1);
  print(newTotal); // <-- prints 15

default value를 줄 수도 있다. Optional value들은 parameter가 대입되지 않더라도 함수에서 살아있다. default value가 미리 정의되어 있었다면 해당값으로, 아니라면 null로 초기화된다.

Optional named

{} 중괄호를 이용하여 named parameter를 정의할 수 있다.

void printName(String firstName, String lastName, {String? suffix}) {
  print('$firstName $lastName ${suffix ?? ''}');
}
// ···
  printName('Avinash', 'Gupta');
  printName('Poshmeister', 'Moneybuckets', suffix: 'IV');

역시 default value를 정의해줄 수 있다.

optional하지 않은 named parameter를 정의해주고 싶다면 required 를 붙여준다.

함수는 optional positional parameter와 optional named parameter를 동시에 가질 수 없다.는 것을 기억하자.

constructor

class MyColor {
  int red;
  int green;
  int blue;

  MyColor(this.red, this.green, this.blue);
}

final color = MyColor(80, 80, 128);

constructor에서 this.를 이용하여 값을 바로 할당할 수 있다!!

named parameter를 이용할수도 있다.

class MyColor {
  ...

  MyColor({required this.red, required this.green, required this.blue});
}

final color = MyColor(red: 80, green: 80, blue: 80);

위 코드에서는 this.green, this.red, this.blue가 모두 required 로 표시된다. 세 변수가 모두 필요하다는 것! default value를 넣는다면 required를 뺼 수도 있다.

MyColor([this.red = 0, this.green = 0, this.blue = 0]);
// or
MyColor({this.red = 0, this.green = 0, this.blue = 0});

named constructor

이름이 없는 constructor는 하나만 정의할 수 있다.

여러 개의 constructor를 만들기 위해서는 이름이 존재하는 named constructor를 이용하자.

class Point {
  double x, y;

  Point(this.x, this.y);

  Point.origin()
      : x = 0,
        y = 0;
}

final myPoint = Point.origin();

: 생성과 동시에 멤버 변수를 초기화하는데 쓰인다

생성자 : 초기화 리스트 {


}

Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

constructor의 body 부분이 실행되기 전에 변수들을 초기화시키기 위해 이용한다.

factory constructors

class Square extends Shape {}

class Circle extends Shape {}

class Shape {
  Shape();

  factory Shape.fromTypeName(String typeName) {
    if (typeName == 'square') return Square();
    if (typeName == 'circle') return Circle();

    print('I don\'t recognize $typeName');
    throw Error();
  }
}

factory 라는 키워드를 이용하여 factory constructor를 정의할 수 있다.

Factory constructor는 subtype이나 null을 리턴할 수 있다.

redirecting constructor

다른 constructor와 연결하는 용도로만 이용되는 constructur가 있을 수 있다. redirecting constructor의 body는 항상 비어있으며, :(colon) 뒤에서 다른 constructor를 호출한다.

class Automobile {
  String make;
  String model;
  int mpg;

  // The main constructor for this class.
  Automobile(this.make, this.model, this.mpg);

  // Delegates to the main constructor.
  Automobile.hybrid(String make, String model) : this(make, model, 60);

  // Delegates to a named constructor
  Automobile.fancyHybrid() : this.hybrid('Futurecar', 'Mark 2');
}

Const constructor

변화가 없는 object를 만들고 싶다면 const constructur를 만들 수도 있다. 단, 모든 instance 변수는 final이 돼야 한다.

class ImmutablePoint {
  const ImmutablePoint(this.x, this.y);

  final int x;
  final int y;

  static const ImmutablePoint origin = ImmutablePoint(0, 0);
}

dart : Iterable

dart에서 Iterable은 추상 클래스다. Iterable로 instance를 생성할 수는 없다는 말이다.

하지만 new List나 Set을 통해 new Iterable을 생성하는 것은 가능하다.

Iterable<int> iterable = [1, 2, 3];

그럼 그냥 List로 정의하는 거랑 똑같지 않냐고? 그렇진 않다. Iterable로 정의하는 순간 우리는 index로 값을 불러올 수 없다. 즉 iterable[1] 과 같은 접근이 불가능해진다는 것. 이는 이러한 접근이 Iterable에는 정의되지 않고 List에만 정의되어 있기 때문이다

대신 쓸 수 있는 것은 iterable.elementAt(1)과 같은 표현이다.

  • for in
var iterable = ['Salad', 'Popcorn', 'Toast'];for (var element in iterable) {	print(element);}

iterable 내의 원소들에 차례대로 접근한다.

그럼 이제 iterable class에서 이용할 수 있는 것들을 알아보자.

원소 접근하기

iterable.first, iterable.last

첫 원소와 마지막 원소에 접근하기 위해서 각각 iterable.first, iterable.last를 이용할 수 있다.

firstWhere()

특정 조건을 만족하는 첫번째 원소를 가져온다.

parameter로 bool을 return하는 condition함수를 넣어준다.

String element = iterable.firstWhere((element) => element.length > 5);

위와 같은 expression은 길이가 5보다 큰 첫번째 element를 찾아내겠지.

  • firstWhere + orElse() : condition을 만족하는 value가 하나도 없을 때의 return 값을 정한다.
// You can also use an `orElse` function in case no value is found!
  var element4 = items.firstWhere(
    (element) => element.length > 10,
    orElse: () => 'None!',
  );
  print(element4);

만약 condition을 만족하는 value가 하나도 없는데 orElse가 정의되지 않았다면 StateError 가 생긴다.

조건문 추가하기

every

모든 원소들이 해당 조건을 만족하는 지 확인한다.

return items.every((element) => element.length >= 5);

any

하나의 원소라도 해당 조건을 만족하면 true

filtering

조건을 만족시키는 모든 원소들을 찾기 위해서는?

where 을 이용한다.

var evenNumbers = numbers.where((number) => number.isEven);

-> numbers중 짝수인 원소들만 모아 새로운 iterable을 만들어준다.

조건을 만족하는 원소가 없으면 그냥 빈 iterable를 리턴한다.

mapping

각 원소들을 받아 함수를 적용하여 대체한다.

Iterable<int> output = numbers.map((number) => number * 10);

모든 원소들에 10을 곱한 새로운 iterable을 만든다.

dart: async library

import 'dart:async';

Future

Future는 실행 결과가 끝나는 미래에 그 값을 반환하는 계산을 가진다. -> Promise 개념

HttpServer.bind('127.0.0.1', 4444)
     .then((server) => print('${server.isBroadcast}'))
     .catchError(print);

위 예제에서 bind() 함수는 Future 타입을 리턴한다.

-> Future.then() : Future가 성공적으로 값을 반환했을 때의 콜백 함수이다.

-> Future.catchError() : Future가 성공적으로 값을 반환하지 않았을 때의 콜백함수이다.

Stream

결과의 시퀀스

profile
개발블로그

0개의 댓글