Flutter를 위한 Dart 언어 기초

Baek Dong Hyun·2022년 12월 7일
1

기본적으로

void main() {
	
}

안에 작성하게 된다.

어떤 언어던 항상 hello world는 찍어봐야하니까 작성법은

void main() {
	print('hello world');
}

위와같이 작성하면 된다.

1. 변수 선언

1-1. var 변수 선언 (걍 쓰지마셈)

void main() {
  var name = '코드팩도리';

  print('name: $name');

  var name2 = '코드공장';

  print('name2 : $name2');

  name = '플러터 프로그래밍';

  print('name: $name');
}

1-2. int 정수 타입 변수 선언

void main() {
  // 정수
  int number1 = 10;
  int number2 = 5;

  print(number1 + number2);
  print(number1 - number2);
  print(number1 * number2);
  print(number1 / number2);
}

1-3. double 실수 타입 번수 선언

void main() {
  // 실수
  double number1 = 2.5;
  double number2 = 0.5;

  print(number1 + number2);
  print(number1 - number2);
  print(number1 * number2);
  print(number1 / number2);
}

1-4. bool boolean(맞다/틀리다) 타입 변수 선언

void main() {
	// boolean
  bool isTrue = true;
  bool isFalse = false;

	print(isTrue);
  print(isFalse);
}

1-5. String 문자 타입 변수 선언

void main() {
	// String
  String name = '코드';

	print(name);
}

1-6. dynamic 어떤 타입이든 다 넣을 수 있는 타입 변수 선언

void main() {
  var name = '코드팩도리';

  // dynamic
  dynamic name3 = '코딩팩토리';

  dynamic number3 = 1;
  
  dynamic number4 = 1.5;

  dynamic isTrue2 = true;
}

얘는 var랑 다른게 var 는 처음에 어떠한 값이던 선언 가능하다. 하지만 값을 변경할 때 다른 타입으로 변경이 불가능하다.

void main() {
	var name = '코드';

	// name = 1; <- 이거 에러남
}

근데 dynamic 은 다른 타입으로도 값을 바꿀 수 있다.

void main() {
	dynamic name = 'code';

	name = 1;
}

2. nullable / non-nullable 차이

2-1. null

아무런 값도 있지 않다.

2-2. nullable

null 이 될 수 있다.

2-3. non-nullable

null 이 될 수 없다.

void main() {
	String name = '코드팩토리';

  // name = null; <- String 타입으로 선언해놓고 null로 왜 바꿈? 안됨 : non-nullable

  String? name2 = '코드팩토리2';

  // name2 = null; <- String? 이렇게 하면 String도 들어올 수 있고 null도 가능함 : nullable

  // print(name2!); <- 이렇게 변수 뒤에 !를 붙여주면 ?랑 반대의 개념 무조건 null 아님!
}

3. final / const / DateTime

3-1. final

final로 선언하면 값을 변경할 수가 없다.

void main() {
  final String name = '코드팩토리';

  print('name $name');

  // name = 'code';
}

3-2. const

const도 마찬가지로 값을 선언하면 변경할 수가 없다.

void main() {
  const String name = '코드팩토리';

  print('name $name');

  // name = 'code';
}

final이나 const로 선언을 하게되면 위처럼 String 같이 선언을 꼭 해줄 필요 없다. (Type 생략가능)

void main() {
  const name1 = '코드팩토리';
  final name2 = 'coding';

  print('name $name1');
  print('name $name2');

}

3-3. DateTime

날짜 시간 관련 ( javascript에선 new Date() )

void main() {
  DateTime now1 = DateTime.now();

  print('now: $now1');

  DateTime now2 = DateTime.now();

  print('now: $now2');

}

DateTime을 실행하면 실행 순간(?)을 각 변수에 저장하고 print로 찍기 때문에 now1과 now2가 찍히는 시간은 다르다.

now1: 2022-12-03 23:47:37.402157
now2: 2022-12-03 23:47:37.403391

이렇게 다르게 출력된다.

3-4. final 과 const 의 차이

void main() {
	final DateTime now1 = DateTime.now();

	// const DateTime now2 = DateTime.now();
}

DateTimefinal 로는 선언 할 수 있지만 const로는 불가능하다.

여기서 차이가 있는데

final빌드타임에 값을 모르고 있어도 되지만 const는 빌드타입에 값을 알고 있어야한다.

빌드타임이란?
우리가 코드를 작성하게되면 컴퓨터가 알 수 있게 2진수로 변환이된다.
근데 저 변환이 되는 시점은 run을 했을 때 빌드가 된다.
이때가 빌드타임이다.

그럼 const로 DateTime이 안되는 이유는

const는 작성하는 이 시점에 값을 알고 있어야한다.

DateTime은 run을 하는 시점 즉 실행되는 시점에 값을 알 수 있다.

그러므로 DateTime은 코드가 실행되는 시점에 값을 알 수 있지만 const는 작성을 하는 시점에 값을 알고 있어야하므로 따라서 const로 DateTime을 선언하는 게 불가능하다.

하지만 final은 상관 없다. 선언할 때 값을 몰라도 되니까…

Nullish coalescing (??)

??

javascript 에서도 있던 연산자인데 ?? 앞에 데이터가 null이면 ?? 다음을 반환한다.

void main() {
  double? number = 4.0;

  print(number);

  number = 2.0;

  print(number);

  number = null;

  print(number);

  number ??= 3.0; // -> number = number ?? 3.0 랑 같은 뜻이고 number = number != null ? number : 3.0 랑도 같다.

  print(number);
}

Type 비교

is

is로 타입을 비교할 수 있다. 비교대상 is type

void main() {
  int number1 = 1;
  
  print(number1 is int);
	print(number1 is String);
}

결과는

true
false

반대로 아닌지를 비교하고싶을 땐 비교대상 is! type

void main() {
  int number1 = 1;
  
  print(number1 is! int);
  print(number1 is! String);
}

결과는

false
true

List

1. 선언 및 작성 방법

List<type> 변수 명 = [ 해당타입에 맞는 값, 해당타입에 맞는 값, 해당타입에 맞는 값 ];
void main() {
	List<String> blackPink = ['제니', '지수', '로제', '리사'];
}

당연히 해당 타입이 아닌 다른 값을 넣으면 에러가 난다.

2. index

배열안 요소들은 각각 index를 가지고 있는데 해당 번째의 요소를 출력할 수 있다.

void main() {
	List<String> blackPink = ['제니', '지수', '로제', '리사'];
	print(blackPink);

	print(blackPink[0]);
	print(blackPink[1]);
	print(blackPink[2]);
	print(blackPink[3]);
	// print(blackPink[4]);
}

결과는

['제니', '지수', '로제', '리사']
제니
지수
로제
리사

배열의 index는 무조건 0번부터 시작한다.

3. [].length

배열의 길이를 알 수 있는 함수이다.

void main() {
	List<String> blackPink = ['제니', '지수', '로제', '리사'];

	print(blackPink.length);
}

결과는

4

길이는 0부터 시작하지 않는다.

4. [].add()

배열에 특정 값을 추가할 때 사용한다.

void main() {
	List<String> blackPink = ['제니', '지수', '로제', '리사'];

	print(blackPink);

	blackPink.add('코드팩토리');

	print(blackPink);
}

결과는

['제니', '지수', '로제', '리사', '코드팩토리']

5. [].remove()

배열의 특정 값을 제거할 때 사용한다.

void main() {
	List<String> blackPink = ['제니', '지수', '로제', '리사'];

	print(blackPink);

	blackPink.add('코드팩토리');

	print(blackPink);

	blackPink.remove('코드팩토리');

	print(blackPink);
}

결과는

['제니', '지수', '로제', '리사', '코드팩토리']
['제니', '지수', '로제', '리사']

6. [].indexOf()

배열의 특정 값이 몇번째인지 알고싶을 때 사용한다.

void main() {
	List<String> blackPink = ['제니', '지수', '로제', '리사'];

	print(blackPink.indexOf('로제'));
}

결과는

2

Map

1. 선언 및 작성방법

Map<key의 type , value의 type> 변수 명 = {key : value, key : value};
void main() {
	Map<String, String> dictionary = {
    'Herry Potter' : '해리포터',
    'Ron Wessley' : '론 위즐리',
    'Hermione Granger' : '헤르미온느 그레인저',
  };

  print(dictionary);
}

결과는

{Herry Potter: 해리포터, Ron Wessley: 론 위즐리, Hermione Granger: 헤르미온느 그레인저}

2. {}.addAll()

여러개의 값을 추가할 때 사용한다.

꼭 Map이 아니더라도 List에도 사용할 수 있음
List<int> numbers = [1,2,3,4];
numbers.addAll([5,6,7,8]);
print(numbers);
하게되면 [1,2,3,4,5,6,7,8] 출력됨

void main() {
	Map<String, String> dictionary = {
    'Herry Potter' : '해리포터',
    'Ron Wessley' : '론 위즐리',
    'Hermione Granger' : '헤르미온느 그레인저',
  };

  print(dictionary);

  dictionary.addAll({'Draco Malfoy' : '드레이코 말포이'});

  print(dictionary);
}

결과는

{Herry Potter: 해리포터, Ron Wessley: 론 위즐리, Hermione Granger: 헤르미온느 그레인저, Draco Malfoy: 드레이코 말포이}

3. [key]

작성한 key의 해당하는 value를 가져올 수 있다.

void main() {
	Map<String, String> dictionary = {
    'Herry Potter' : '해리포터',
    'Ron Wessley' : '론 위즐리',
    'Hermione Granger' : '헤르미온느 그레인저',
		'Draco Malfoy' : '드레이코 말포이'
  };

  print(dictionary['Herry Potter']);
	
}

결과는

해리포터

또 해당 리스트에 없는 값을 추가할 수도 있다

void main() {
	Map<String, String> dictionary = {
    'Herry Potter' : '해리포터',
    'Ron Wessley' : '론 위즐리',
    'Hermione Granger' : '헤르미온느 그레인저',
		'Draco Malfoy' : '드레이코 말포이'
  };

  print(dictionary['Herry Potter']);

	dictionary['Tom Riddle'] = '볼드모트';

	print(dictionary);
	
}

결과는

{Herry Potter: 해리포터, Ron Wessley: 론 위즐리, Hermione Granger: 헤르미온느 그레인저, Draco Malfoy: 드레이코 말포이, Tom Riddle: 볼드모트}

4. {}.keys , {}.values

  • .keys 는 해당하는 Map에 key들을 출력할 수 있다.
  • .values 는 해당하는 Map에 value들을 출력할 수 있다.
void main() {
  Map<String, String> dictionary = {
    'Herry Potter' : '해리포터',
    'Ron Wessley' : '론 위즐리',
    'Hermione Granger' : '헤르미온느 그레인저',
    'Draco Malfoy' : '드레이코 말포이',
    'Tom Riddle' :  '볼드모트',
  };

  print(dictionary);

  print(dictionary.keys);
  print(dictionary.values);
}

결과는

{Herry Potter: 해리포터, Ron Wessley: 론 위즐리, Hermione Granger: 헤르미온느 그레인저, Draco Malfoy: 드레이코 말포이, Tom Riddle: 볼드모트}
(Herry Potter, Ron Wessley, Hermione Granger, Draco Malfoy, Tom Riddle)
(해리포터, 론 위즐리, 헤르미온느 그레인저, 드레이코 말포이, 볼드모트)

Set

1. 선언 및 작성방법

Set<type> 변수 명 = {value1, value2};

Set은 Map과 비슷하게 {} 안에 작성한다. 하지만 그렇다고 Map과 같지는 않는데 Map이 key와 value로 이루어져 있다면, Set은 그냥 값만 넣는다. 그렇다고 List와 같지는 않는다. 위에 적혀있다시피 List는 [] 안에 작성하고 Set은 {} 안에 작성한다. 그렇다고 괄호의 차이만 있는 것도 아니다. List는 중복값을 허용하지만 Set은 중복값을 허용하진않는다.

void main() {
	Set<String> names = {'코드 팩토리', 'flutter', 'flutter'};

  print(names);
}

결과는

{코드 팩토리, flutter}

2. .add() , .remove()

위 List 와 마찬가지로 값을 추가하고 삭제할 수 있다.

void main() {
	final Set<String> names = {'코드 팩토리', 'flutter'};

  print(names);

  names.add('javascript');

  print(names);

  names.remove('javascript');

  print(names);
}

결과는

{코드 팩토리, flutter}
{코드 팩토리, flutter, javascript}
{코드 팩토리, flutter}

3. .contains()

특정값이 있는지 없는지 확인할 때 사용한다. 결과는 boolean값으로 나온다.

void main() {
	final Set<String> names = {'코드 팩토리', 'flutter'};

  print(names);

  names.add('javascript');

  print(names);

  names.remove('javascript');

  print(names);

  print(names.contains('javascript'));
  print(names.contains('flutter'));
}

결과는

{코드 팩토리, flutter}
{코드 팩토리, flutter, javascript}
{코드 팩토리, flutter}
false
true

enum

참고 사이트 ( https://dajoonee.tistory.com/30 )

0. enum 타입은 언제 사용함?

  • 한정된 상수 값 집합을 나타내기 위해 사용한다.
  • 직관적인 코드 작성에 용이하다.

1. 선언 및 작성 방법

  • 열거형의 명칭은 첫 문자를 대문자로 써야함
  • 앞에 enum 키워드를 붙인다.
  • 중괄호 블록에 필드로 상수값들을 나열한다.

enum은 조금 특이한 형태인데 main함수 밖에 선언해줘야한다.

enum 이름 {
  // 여기에 작성하면 된다. 
}

void main() {
  // enum

}
enum Status {
  approved, // 승인
  pending, // 대기
  rejected, // 거절
}

void main() {
  // enum
  Status status = Status.pending;

  switch(status) {
    
    case Status.approved:
      // TODO: Handle this case.
      print('승인입니다.');
      break;
    case Status.pending:
      // TODO: Handle this case.
      print('대기입니다.');
      break;
    case Status.rejected:
      // TODO: Handle this case.
      print('거절입니다.');
      break;
    default:
      print('잘못된 상태입니다.');
      break;
  }
}

결과는

대기입니다.

2. 목록 읽기

  • 상수 목록은 List와 마찬가지로 인덱스로 관리가 가능
  • 전체의 값을 읽을 때는 .values를 사용
enum Status {
  approved, // 승인
  pending, // 대기
  rejected, // 거절
}

void main() {
	print(Status.values);
}

결과는

[Status.approved, Status.pending, Status.rejected]

함수 선언

예를 들어 세개의 숫자를 더하고 짝수인지 홀수인지 알려주는 함수를 만들어보면

1. 선언 및 작성 방법

반환타입 함수명(parameter) {
	함수 내용 작성
	
	return
}

반환타입이 void라면 return을 작성할 필요가 없다.

2. positional parameter

아래와 같이 값을 받아야하고 값의 순서 ( ex. 지금은 x + y + z라면 만약 (x + y) z 처럼 식이 바꼈다면 넣는 위치가 되게 중요하다. 계산한 토탈 값이 5가 될 수도 9가 될 수 있기 때문이다.* )가 중요한 파라마터positional parameter라고 한다.

void main() {
  addNumbers(1, 2, 3);
}

void addNumbers(int x , int y , int z) {
  int sum = x + y + z;

  if (sum % 2 == 0) {
    print('짝수입니다.');
  } else {
    print('홀수입니다.');
  }
}

3. optional parameter

있어도 되고 없어도되는 파라미터는 optional parameter라고 한다.

void main() {
  optionalAddNumbers(2);
  optionalAddNumbers(1,1,2);
}

// optional parameter => 있어도되고 없어도 되는 파라미터
void optionalAddNumbers(int x , [int y = 2, int z = 3]) {
  int sum = x + y + z;

  if (sum % 2 == 0) {
    print('optional 짝수입니다.');
  } else {
    print('optional 홀수입니다.');
  }
}

기본값을 [int y = 2, int z = 3] 이렇게 넣으면 값을 안넣게 되면 기본값으로 들어가고 값을 넣게되면 기본값은 무시된다.

4. named parameter

이름이 있는 파라미터( 순서가 중요하지않다. ) 는 named parameter라고 한다.

파라미터 넣는 곳에 {} 를 하고 그 안에 required를 넣으면 필수로 넣어하하는 값 , required를 넣지 않고 뒤에 기본 값을 넣어주면 optional parameter 처럼 사용 가능

void main() {
  namedAddNumbers(x: 1, y: 3, z: 3);
  namedAddNumbers(z: 4, x: 3, y: 2 );
}

// named parameter => 이름이 있는 파라미터 (순서가 중요하지 않다.)
void namedAddNumbers({ required int x, required int y, int z = 3 }) {
  int sum = x + y + z;

  if (sum % 2 == 0) {
    print('optional 짝수입니다.');
  } else {
    print('optional 홀수입니다.');
  }
}

5. positional parameter + named parameter

두가지를 같이 사용할 수 있다.

void main() {
  shareAddNumbers(1, y: 3);
}

int shareAddNumbers(int x, { required int y, int z = 10 }) {
  int sum = x + y + z;

  return sum;
}

6. arrow function (화살표 함수)

javascript 의 arrow function이랑 비슷하지만 그렇다고 같지는 않다. 한 줄로 처리가 가능 할 경우에 사용 가능하다.

5번에 적힌 함수를 한줄로 처리하면

int arrowShareAddNumbers(int x, { required int y, int z = 10 }) => x + y + z;

이렇게 가능하다.

typedef

함수를 변수처럼 사용할 수 있게 해줌.

1. 선언 및 작성 방법

typedef 이름 = type Fucntion(parameter);
void main() {
  // typedef로 더하기 가져다 쓰기
  Operation operation = add;

  int result = operation(1,2,3);

  print(result);

  // 빼기로 바꿔서 써보기
  operation = subtract;

  result = operation(3,2,1);

  print(result);
}

// typedef

// signature
typedef Operation = int Function(int x , int y , int z);

// +
int add(int x , int y , int z) => x + y + z;
// -
int subtract(int x , int y , int z) => x - y - z;

가져다가 쓸 때는 꼭 typedef에 작성한 파라미터가 같아야한다. typedef의 이름은 꼭 대문자로!

근데 이런식으로 사용하지는 않는다.

void main() {
  
  int result2 = calculate(1,2,3,add);

  print(result2);

  int result3 = calculate(3, 2, 1, subtract);

  print(result3);
}

// typedef

// signature
typedef Operation = int Function(int x , int y , int z);

// +
int add(int x , int y , int z) => x + y + z;
// -
int subtract(int x , int y , int z) => x - y - z;

// 계산
int calculate(int x, int y, int z, Operation operation) {

  return operation(x, y, z);
}

이런식으로 사용한다고 한다.

calculate 라는 함수를 만들고 그 파라미터에 typedef로 만든 operation를 담는다. 해당 함수는 int를 반환하고 operation도 int를 반환하는 함수이다. 그래서 calculate함수의 return은 operation가 될 수 있다.

profile
안녕하세요.

4개의 댓글

comment-user-thumbnail
2022년 12월 7일

야무지네요

1개의 답글