기본적으로
void main() {
}
안에 작성하게 된다.
어떤 언어던 항상 hello world는 찍어봐야하니까 작성법은
void main() {
print('hello world');
}
위와같이 작성하면 된다.
void main() {
var name = '코드팩도리';
print('name: $name');
var name2 = '코드공장';
print('name2 : $name2');
name = '플러터 프로그래밍';
print('name: $name');
}
void main() {
// 정수
int number1 = 10;
int number2 = 5;
print(number1 + number2);
print(number1 - number2);
print(number1 * number2);
print(number1 / number2);
}
void main() {
// 실수
double number1 = 2.5;
double number2 = 0.5;
print(number1 + number2);
print(number1 - number2);
print(number1 * number2);
print(number1 / number2);
}
void main() {
// boolean
bool isTrue = true;
bool isFalse = false;
print(isTrue);
print(isFalse);
}
void main() {
// String
String name = '코드';
print(name);
}
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;
}
아무런 값도 있지 않다.
null 이 될 수 있다.
null 이 될 수 없다.
void main() {
String name = '코드팩토리';
// name = null; <- String 타입으로 선언해놓고 null로 왜 바꿈? 안됨 : non-nullable
String? name2 = '코드팩토리2';
// name2 = null; <- String? 이렇게 하면 String도 들어올 수 있고 null도 가능함 : nullable
// print(name2!); <- 이렇게 변수 뒤에 !를 붙여주면 ?랑 반대의 개념 무조건 null 아님!
}
final로 선언하면 값을 변경할 수가 없다.
void main() {
final String name = '코드팩토리';
print('name $name');
// name = 'code';
}
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');
}
날짜 시간 관련 ( 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
이렇게 다르게 출력된다.
void main() {
final DateTime now1 = DateTime.now();
// const DateTime now2 = DateTime.now();
}
DateTime은 final 로는 선언 할 수 있지만 const로는 불가능하다.
여기서 차이가 있는데
final은 빌드타임에 값을 모르고 있어도 되지만 const는 빌드타입에 값을 알고 있어야한다.
빌드타임이란?
우리가 코드를 작성하게되면 컴퓨터가 알 수 있게 2진수로 변환이된다.
근데 저 변환이 되는 시점은 run을 했을 때 빌드가 된다.
이때가 빌드타임이다.
그럼 const로 DateTime이 안되는 이유는
const는 작성하는 이 시점에 값을 알고 있어야한다.
DateTime은 run을 하는 시점 즉 실행되는 시점에 값을 알 수 있다.
그러므로 DateTime은 코드가 실행되는 시점에 값을 알 수 있지만 const는 작성을 하는 시점에 값을 알고 있어야하므로 따라서 const로 DateTime을 선언하는 게 불가능하다.
하지만 final은 상관 없다. 선언할 때 값을 몰라도 되니까…
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);
}
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<type> 변수 명 = [ 해당타입에 맞는 값, 해당타입에 맞는 값, 해당타입에 맞는 값 ];
void main() {
List<String> blackPink = ['제니', '지수', '로제', '리사'];
}
당연히 해당 타입이 아닌 다른 값을 넣으면 에러가 난다.
배열안 요소들은 각각 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번부터 시작한다.
배열의 길이를 알 수 있는 함수이다.
void main() {
List<String> blackPink = ['제니', '지수', '로제', '리사'];
print(blackPink.length);
}
결과는
4
길이는 0부터 시작하지 않는다.
배열에 특정 값을 추가할 때 사용한다.
void main() {
List<String> blackPink = ['제니', '지수', '로제', '리사'];
print(blackPink);
blackPink.add('코드팩토리');
print(blackPink);
}
결과는
['제니', '지수', '로제', '리사', '코드팩토리']
배열의 특정 값을 제거할 때 사용한다.
void main() {
List<String> blackPink = ['제니', '지수', '로제', '리사'];
print(blackPink);
blackPink.add('코드팩토리');
print(blackPink);
blackPink.remove('코드팩토리');
print(blackPink);
}
결과는
['제니', '지수', '로제', '리사', '코드팩토리']
['제니', '지수', '로제', '리사']
배열의 특정 값이 몇번째인지 알고싶을 때 사용한다.
void main() {
List<String> blackPink = ['제니', '지수', '로제', '리사'];
print(blackPink.indexOf('로제'));
}
결과는
2
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: 헤르미온느 그레인저}
여러개의 값을 추가할 때 사용한다.
꼭 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: 드레이코 말포이}
작성한 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: 볼드모트}
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<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}
위 List 와 마찬가지로 값을 추가하고 삭제할 수 있다.
void main() {
final Set<String> names = {'코드 팩토리', 'flutter'};
print(names);
names.add('javascript');
print(names);
names.remove('javascript');
print(names);
}
결과는
{코드 팩토리, flutter}
{코드 팩토리, flutter, javascript}
{코드 팩토리, flutter}
특정값이 있는지 없는지 확인할 때 사용한다. 결과는 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
참고 사이트 ( https://dajoonee.tistory.com/30 )
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;
}
}
결과는
대기입니다.
enum Status {
approved, // 승인
pending, // 대기
rejected, // 거절
}
void main() {
print(Status.values);
}
결과는
[Status.approved, Status.pending, Status.rejected]
예를 들어 세개의 숫자를 더하고 짝수인지 홀수인지 알려주는 함수를 만들어보면
반환타입 함수명(parameter) {
함수 내용 작성
return
}
반환타입이 void라면 return을 작성할 필요가 없다.
아래와 같이 값을 받아야하고 값의 순서 ( 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('홀수입니다.');
}
}
있어도 되고 없어도되는 파라미터는 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] 이렇게 넣으면 값을 안넣게 되면 기본값으로 들어가고 값을 넣게되면 기본값은 무시된다.
이름이 있는 파라미터( 순서가 중요하지않다. ) 는 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 홀수입니다.');
}
}
두가지를 같이 사용할 수 있다.
void main() {
shareAddNumbers(1, y: 3);
}
int shareAddNumbers(int x, { required int y, int z = 10 }) {
int sum = x + y + z;
return sum;
}
javascript 의 arrow function이랑 비슷하지만 그렇다고 같지는 않다. 한 줄로 처리가 가능 할 경우에 사용 가능하다.
5번에 적힌 함수를 한줄로 처리하면
int arrowShareAddNumbers(int x, { required int y, int z = 10 }) => x + y + z;
이렇게 가능하다.
함수를 변수처럼 사용할 수 있게 해줌.
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가 될 수 있다.
야무지네요