Dart 심화 문법 (class, list, map)
Updated:
1.class 선언 및 constructor
-
비슷한 성격, 기능들의 변수와 함수를 모아 놓는것이 class 라고 합니다.
-
class 의 명을 항상 대문자로 시작합니다
void main() {
// Instantiation 인스턴스화 class 를 instance 로 바꾸는것
People yourName = People('Jacob', '학생');
yourName.sayName(); // 제 이름은 Jacob 입니다 / 제 직업은 학생 입니다
print(yourName.name); // Jacob
print(yourName.group); // 학생
}
class People {
String name;
String group;
// constructor 생성 : class 가 처음 선언이 되었을때 원하는 변수를 class 안에 집어 넣을 수 있는 기능
People(
String name,
String group,
) : this.name = name,
this.group = group;
void sayName() {
print('제 이름은 ${this.name} 입니다');
print('제 직업은 ${this.group} 입니다');
}
}
Named constructor
- Named constructor 를 사용하게되면 한 class 안에서 여러개의 constructor 를 생성할 수 있게 됨, class 를 여러가지로 인스턴스화 할 수 있다는 것입니다
void main() {
// Instantiation 인스턴스화 class 를 instance 로 바꾸는것
People yourName = People('Jacob', '학생');
yourName.sayName(); // 제 이름은 Jacob 입니다 / 제 직업은 학생 입니다
print(yourName.name); // Jacob
print(yourName.group); // 학생
People newMenber = People.fromMap({'name': 'John', 'group': '회사원'});
newMenber.sayName(); //제 이름은 John 입니다 제 직업은 회사원 입니다
print(newMenber.name); // John
print(newMenber.group); // 회사원
}
class People {
String name;
String group;
// constructor 생성 : class 가 처음 선언이 되었을때 원하는 변수를 class 안에 집어 넣을 수 있는 기능
// final 을 사용하게 되면 class 안에서 무조건 적으로 변수를 선언해야 되고, 그 해당 변수들은 class 안에 생성되게 되면 그 뒤로는 변수의 값을 바꿀 수 없게 할 수 있음
People(
final String name,
final String group,
) : this.name = name,
this.group = group;
// Named constructor
People.fromMap(
Map input,
) : this.name = input['name'],
this.group = input['group'];
void sayName() {
print('제 이름은 ${this.name} 입니다');
print('제 직업은 ${this.group} 입니다');
}
}
2.Getter and Setter
-
Getter -> 값을 가져올때
-
Setter -> 값을 변경할때
-
변수에 _ underScore 를 붙이는 것을 Private variable 이라고 함. 이것을 왜 쓰냐면 전통적인 OOP 를 하는 Java 같은데서는 class 안에서만 private 변수들을 가져 올수 있습니다. 근데 dart 는 특이하게 같은 파일에서 작성이 되었을때만 private 변수를 가져 올 수 있습니다.
-
만약 class 가 다른 파일에 있고, main 함수에서 class 를 import 해서 사용해야될 경우에 private 변수를 사용할때 error 가 발생됨
-
그래서 그것을 가져오기 위해서 getter 와 setter 를 사용합니다.
-
일반적으로 private 변수나 뭔가 바꾸려고 할때, getter 와 setter 를 사용하고 그 외의 경우에는 함수를 주로 사용하게 됩니다
void main() {
// instance
Staff jacob = Staff('Jacob', 30);
jacob.sayName(); // 저는 Jacob 입니다
print(jacob._name); // Jacob
// getter 의 name 임
print(jacob.name); // Jacob
// setter 를 사용해서 값 변경
jacob.name2 = 'Emma';
print(jacob.name); // Emma
}
class Staff {
String _name;
int _age;
// Constructor
Staff(
String name,
int age,
) : this._name = name,
this._age = age;
void sayName() {
print('저는 ${this._name} 입니다');
}
// getter 값을 가져와서 return 해줌
get name {
return this._name;
}
// setter 는 값을 바꿀때 사용
// 한개의 parameter 를 사용해서 나중에 호출할때 값을 바꿀수 있다
set name2(String name) {
this._name = name;
}
}
3.Class inheritance (상속)
-
상속에는 부모 class 가 있고, 자식 class 가 있습니다. 부모는 여러개의 자식 class 가 있고, 자식 class 는 부모에 종속된 하나의 class 를 말합니다.
-
부모의 class 는 자식의 class 를 상속받지 않습니다
-
자식 class 에서 부모는 하나밖에 연결할 수 없습니다.
-
자식 class 끼리는 서로 상속되지 않습니다
void main() {
// instance
Staff jacob = Staff('Jacob', 40);
jacob.sayNmae(); // 저는 Jacob 입니다
jacob.sayAge(); // 저의 나이는 40 입니다
// 상속받은 People
People john = People('John', 20);
print(john.name); // 저는 John 입니다
}
class Staff {
String name;
int age;
// constructure
Staff(String name, int age)
: this.name = name,
this.age = age;
void sayNmae() {
print('저는 ${this.name} 입니다');
}
void sayAge() {
print('저의 나이는 ${this.age} 입니다');
}
}
// extends - 상속할때 사용, staff 의 있는 내용을 다 상속 받게 됩니다
// super 를 사용하게 되면 부모 class 의 constructure 를 가리키게 됨
class People extends Staff {
// constructure
People(
String name,
int age,
) : super(name: name, age: age);
}
class Hero {
String name = 'Jacob';
void run() {}
}
class SuperHero extends Hero {
@override
void run() {
super.run(); // 부모의 run() 실행
this.fly(); // 추가로 class 안에 fly 실행
}
void fly() {}
}
void main() {
var hero = SuperHero();
hero.run();
hero.fly();
print(hero.name); // Jacob
}
4.Method overriding
-
method 란? class 안의 함수를 가리킵니다
-
만약 자식 class 에서 함수 class 를 override 하고 싶으면, @override 를 사용하고, 부모 class 에서 무언가 사용하고자 한다면 super 를 사용해서 가져와서 사용할 수 있습니다
void main() {
Parnet parnet = Parnet(3);
Child child = Child(3);
print(parnet.calculate()); // 9
// override 를 통해서 부모의 claculate() 함수를 바꿨음
print(child.calculate()); // 9 에서 6으로 바꿈 또, result 로 super 를 사용해면 18 이 나옴
}
class Parnet {
final int number;
Parnet(
int number,
) : this.number = number;
// function = class 안에 있는 함수라서 Method 라고 함
int calculate() {
return this.number * this.number;
}
}
class Child extends Parnet {
Child(
int number,
) : super(
number,
);
// decorator
// override 를 사용해서 자식 class 에서 기존에 있는 method 를 덮어쓰기 하는것
@override
int calculate() {
// override 안에 super 를 사용해서 덮어 쓰기 한다음에 사용할 수 있음
int result = super.calculate(); // 3 * 3 해서 9 가 나옴
return result + result; // 9 + 9 = 18
}
}
5.Class static keyword
-
일반적으로 instance 에 귀속이 되지 않고 class 의 통채로 뭔가 귀속이 될때 사용되는것이 static keyword 입니다
-
static keyword 는 한번만 변경시키면 모든 keyword 에서 변경이 됩니다.
void main() {
Staff jacob = Staff('Jacob');
Staff emma = Staff('Emma');
// static keyword 를 값을 넣는것
Staff.building = 'A 동';
jacob.printNameAndBuilding(); // 제 이름은 Jacob 입니다. A동 건물에서 근무하고 있습니다.
}
// Staff 안에는 직원 소속 건물 - 모든 직원들이 다 같은 건물 있을때
// 직원의 이름 - 이름은 사람마다 다 다름
class Staff {
// 모두 똑같이 공통 사항일때는 static 을 사용해서 building 에 붙여서 사용
static String building;
String name;
Staff(
String name,
) : this.name = name;
void printNameAndBuilding() {
print('제 이름은 ${this.name} 입니다. $building 건물에서 근무하고 있습니다');
}
}
6.super와 this 의 차이
void main() {
Engineer member = Engineer(['Dart', 'Java', 'JS'], 'Jacob', 'A동');
print(member.language); // [Dart, Java, JS]
print(member.building); // A동
print(member.name); // Jacob
member
.sayInfo(); // 저의 이름은 Jacob 입니다. 제가근무하는 빌딩은 A동 제가 할 수 있는 언어는 Dart,Java,JS 입니다
}
class Staff {
final String building;
final String name;
Staff(
String building,
String name,
) : this.building = building,
this.name = name;
}
// 사용할줄 언어를 리스트로 추가하기
class Engineer extends Staff {
List<String> language;
Engineer(
List<String> language,
String name,
String building,
) : this.language = language,
super(
building,
name,
);
void sayInfo() {
// super.name 은 위에서 상속 받았으니까 super 라고 사용하긴 하는데, this.building 은 class 안에 사용했는데 똑같이 A동 을 출력 받았음 실제로 상속을 받을때는 모든것을 다 받기 때문에 class Engineer 에서 선언된 변수가 없더라도, 실제로 존재하는것처럼 보이게 됨
// 자식에서 name을 선언을 해버리면 this 의 값이 우선되게 override 되기 때문에 그때는 class 안에 있는 값으로 this 로 불러와야 됨
print(
'저의 이름은 ${super.name} 입니다. 제가근무하는 빌딩은 ${this.building} 제가 할 수 있는 언어는 ${this.language.join(',')} 입니다');
}
}
7.interface
-
class 가 꼭 선언해야되는 method 랑 변수들을 지정하게 해주는 기능을 함
-
interface를 사용하는 이유는 비슷한 성격을 가지고 있는 class 들은 꼭 이 변수와 함수를 가지고 있으면 좋겠다는 의미 라는 가정이 있을때 주로 사용됩니다
-
interface 같은 경우에는 무조건 그것을 상속해라는 것을 말하는것
-
강제되는 성격에 무언가를 만들고 싶다고 하면 interface 를 사용면 됩니다
void main() {
AGroup bts = AGroup('BTS');
bts.sayName();
}
// 변수명과 함수에 이름만 지정을 한것임
class StaffInterface {
final String name;
StaffInterface(String name) : this.name = name;
void sayName() {}
}
// implements 로 interface에 있는 것들을 AGroup 에서 반드시 선언을 해줘야 함
class AGroup implements StaffInterface {
String name;
AGroup(
String name,
) : this.name = name;
void sayName() {
print('제 이름은 ${this.name} 입니다');
}
}
class BGroup implements StaffInterface{
String name;
AGroup(
String name,
) : this.name = name;
void sayName() {
print('제 이름은 ${this.name} 입니다');
}
}
8.cascade operator
- method 를 작성할때 .. 을 2번 찍어서 사용하는 방식을 말함
void main() {
Staff staff = Staff('Jacob', 'A');
// staff 를 반복적으로 사용해서 호출해야 됨
staff.sayName(); // 제 이름은 Jacob 입니다
staff.sayGroup(); // 저는 A 소속입니다
// 변수도 선언하지 않고 간단하게 .. cascade operator 를 사용해서 class 에 함수를 호출 할 수 있습니다
// 주의 할 점은 맨 마지막에 ; 을 붙인다는 것임
Staff('Emma', 'B')
..sayName() //제 이름은 Emma 입니다
..sayGroup(); // 저는 B 소속입니다
}
class Staff {
String name;
String group;
Staff(
String name,
String group,
) : this.name = name,
this.group = group;
void sayName() {
print('제 이름은 ${this.name} 입니다');
}
void sayGroup() {
print('저는 ${this.group} 소속입니다');
}
}
9.List 심화 (forEach, map, reduce, fold)
forEach (looping)
- return 값을 안받고 그 안에서 도는것
void main() {
List<String> staff = [
'Jacob',
'Emma',
'John',
'Mike',
];
// forEach 람다식으로 JS 의 arrow function 처럼 사용
staff.forEach((e) => print(e));
// 각각의 값을 loop 돌면서 하나씩 출력함
// 위와 똑같은 for loop
for (String element in staff) {
print(element);
}
}
map (mapping)
-
forEach()
와 다르게return
값을 받을 수 있는데, 각각 값에 새로운 값을 넣어줌 -
map
도forEach
와 같이 처음부터 각각의 값으로 lopping 하게 됩니다. 근데 return 되는 값으로 각각 값을 변경 시킵니다. 새로운 list 를 return 해주게 됨
void main() {
List<String> staff = [
'Jacob',
'Emma',
'John',
'Mike',
];
// map
final sayName = staff.map((e) => '제 이름은 $e 입니다');
print(sayName);
// (제 이름은 Jacob 입니다, 제 이름은 Emma 입니다, 제 이름은 John 입니다, 제 이름은 Mike 입니다)
// 기존의 변수는 변경되지 않은것이 확인됨
print(staff); // [Jacob, Emma, John, Mike]
// 특이점은 map 의 return 값을 출력하게 되면 리스트의 형식이 [] => () 로 바껴있다. 왜냐면 map 은 iterable 을 return 해주기 때문 iterable 은 list 보다 부모 class 라고 보면 되는데 실제로는 list 형태로 많이 사용되기 때문에 .toList() 로 형변환 해주면 됨
// [제 이름은 Jacob 입니다, 제 이름은 Emma 입니다, 제 이름은 John 입니다, 제 이름은 Mike 입니다]
// print(sayName.toList());
}
reduce, fold
-
fold()
는 각각의 값들을 mapping 해가면서 그 값들을 이용해서 total 을 쌓아 가는 역활을 합니다. -
reduce()
는 기본적으로 첫번째 값이 설정되어 있는 상태에서fold()
와 비슷하지만,reduce
의 주의 사항은 들어오늘 값과 return 하는 값과 type 이 같아 야 한다 -
fold()
는 type 이 같지 않아도 된다
void main() {
List<int> numbers = [0, 1, 2, 3, 4, 5];
// fold(처음에 시작하는 값, (계속 누적되는 값, maping 되면서 하나씩 보이는 값) => 연산)
int total =
numbers.fold(0, (previousValue, element) => previousValue + element);
print(total); // 15
// reduce() 는 fold 와 비교 했을때, 시작하는 값을 넣지 않아도 됨 reduce는 기본 값으로 항상 첫번째 값이 들어가게 되어 있음 그래서 생략을 하는것임
int total2 = numbers.reduce((value, element) => value + element);
print(total2);
// reduce() 가 type 이 같은때는 간단한데 fold 가 필요한경우는 type 이 다를때 주로 사용됨
List<String> names = ['Jacob', 'Emma', 'John'];
int total3 =
names.fold(0, (previousValue, element) => previousValue + element.length);
print(total3); // list 의 총 글자의 갯수를 int 형태로 return 받을 수 있다
}
10.Map 심화 (entries, asMap)
-
entries
를 사용해서 key, value 값을 전부 끌어다가 사용을 함 -
asMap()
: 맵 형태 key : value 형태로 바꿔주는것 (index 번호: 실제 value 이런식으로 list 를 map 으로 바꿀 수 있음)
void main() {
Map map = {
'Apple': '사과',
'Banana': '바나나',
'Kiwi': '키위',
};
// iterable 값으로 return 됨
print(map.keys); // (Apple, Banana, Kiwi)
print(map.values); // (사과, 바나나, 키위)
// 리스트로 바꾸기 - list 로 바꾸면 list 에 매소드를 다 사용할 수 있게 됨
print(map.keys.toList()); // [Apple, Banana, Kiwi]
print(map.values.toList()); // [사과, 바나나, 키위]
// map 에서 mapping 하기 => entry
// enrty 는 key 값과 value 값들을 다 가져 올 수 있음
final newMap = map.entries.map((e) {
final keys = e.key;
final value = e.value;
return '$keys 는 한글로 $value 입니다';
});
print(
newMap); // (Apple 는 한글로 사과 입니다, Banana 는 한글로 바나나 입니다, Kiwi 는 한글로 키위 입니다)
// entry 를 사용해서 forEach, reduce, fold 등을 다 사용할 수 있습니다.
map.entries.forEach((element) {
final key1 = element.key;
final value1 = element.value;
print('$key1 는 한글로 $value1 입니다');
}); // Apple 는 한글로 사과 입니다
// Banana 는 한글로 바나나 입니다
// Kiwi 는 한글로 키위 입니다
// asMap()
List<int> numbers = [1, 2, 3, 4, 5, 6, 7];
final newMap3 = numbers.asMap();
print(newMap3); // {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7}
// index를 가져 올수 있기 때문에 응용해서
final newMap4 = numbers.asMap().entries.map((e) {
final index = e.key;
final value = e.value;
return 'index 가 $index 일때 값은 $value 입니다';
});
print(newMap4);
// (index 가 0 일때 값은 1 입니다, index 가 1 일때 값은 2 입니다, index 가 2 일때 값은 3 입니다, ..., index 가 5 일때 값은 6 입니다, index 가 6 일때 값은 7 입니다)
}
🔶 🔷 📌 🔑
Leave a comment