var type
- 어떤 타입의 변수든 선언이 가능하다.
- 하지만 한번 선언하고 나면 해당 타입으로 고정된다.
- 때문에 선언 후에 다른 타입으로 대체하여 사용 불가능하다.
- 참고 : 선언 시 값을 지정하지 않아 type인식이 되지 않으면 dynamic type처럼 타입변경이 가능하다.
dynamic type
- var type과 다르게 한번 변수의 타입이 지정되어도 다른 변수타입으로 바꿀 수 있다.
- 협업의 관점에서, 타인이 코드를 봤을 때 명료한 이해를 어렵게 만드므로 사용을 권장하지 않는다.
- String 첫 스펠링을 대문자로 시작한다.
- print함수 사용시 $변수이름 으로 할당이 가능하다.
void main(){
String lname = 'hong';
String fname = 'gildong';
print('$fname ${lname}');
}
출력 : gildong hong
람다식과 익명함수
void main(){
routine((){ // 익명함수 -> 함수의 이름이 없음. 바로 함수를 넣어준다.
return "짜파게티 먹기";
});
routine(()=>"삼양라면 먹기"); // 람다식은 무조건 리턴
}
void routine(Function start){
String result = start();
print(result);
}
/*
간결하게 사용할때는 람다식을 쓴다.
간단히 호출시? 사용한다.
*/
선택적 매개변수
//선택적 매개변수
class Dog {
String name;
int age;
String color;
int thirty;
//인스턴스 함수의 매개변수들을 중괄호로 묶으면 선택전 매개변수화 시킬 수 있다.
Dog({this.name, this.age, this.color, this.thirty});
}
void main(){
// 순서상관이 없어지고 모든 변수를 할당할 필요가 없어진다.
Dog d1 = Dog(name: "Toto", age: 13, color: "white", thirty: 100);
Dog d2 = Dog(name: "Mimi", thirty: 50);
}
cascade 연산자 (계단표기법) ..
class Chef {
void cook(){
print("start cooking");
}
void handWash(){
print("wash a hand");
}
}
// 이 함수는 수정불가능 하다고 가정
void goCompany(Chef c){
c.cook();
}
void main(){
// 객채를 넘지면서 함수를 실행할 수 있다.
goCompany(Chef()..handWash()..cook());
}
상속과 initializer keyword
class Burgur {
String name;
Burgur(this.name){
print(name);
}
}
class CheeseBurgur extends Burgur{
//initializer keyword - ": super(name)"
// CheeseBurgur()의 내부가 실행되기 전에 버거가 실행된다. 따라서 Burgur()에서 name을 찍으면 null 이 나온다.
// 하지만 이니셜라이져 키워드를 이용하여 super에게 name을 넘겨줄 수 있다.
// 그러면 Burgur실행히 name이 초기화가 되어지기 때문에 "치즈햄버거"가 출력된다.
// 즉 부모가 생성될때 값을 넘기기위해 이니셜라이져 키워드를 사용한다.
CheeseBurgur(String name) : super(name){
super.name = name;
}
}
void main(){
Burgur cb = CheeseBurgur("치즈햄버거");
}
mixin
class Engine {
int power = 5000;
}
// 믹스인 : 코드재사용을 위해 사용한다.
class BMW with Engine{
}
void main(){
BMW bm = BMW();
print(bm.power);
// 출력 : 5000
}
추상클래스 abstract class
abstract class Animal { // 추상클래스, abstract class
void sound();
}
class Dog implements Animal{
void sound(){
print("멍멍 배고파");
}
}
class Cat implements Animal{
void sound(){
print("야옹 배고파");
}
}
class Fish implements Animal{
@override // --> 부모의 함수를 무효화시킨다.
void sound() {
print("뻐끔뻐끔 배고파"); // --> 재정의한다.
}
}
void main(){
Dog d1 = Dog();
Cat c1 = Cat();
Fish f1 = Fish();
d1.sound();
c1.sound();
f1.sound();
//멍멍 배고파
//야옹 배고파
//뻐끔뻐끔 배고파
}
List, Map(collection)
//컬랙션 (수집된 물품들)
// int,double, String, bool
// 이들은 커스텀 자료형
class User {
int id=1;
String username="cos";
}
void main(){
// List
List<int> nums = [1,2,3,4];
print(nums); // [1, 2, 3, 4]
var nums2 = [3,4,5];
print(nums2); // [3, 4, 5]
//Map
Map<String, dynamic> user = {
"id":1,
"username":"cos"
};
print(user["id"]); // 1
print(user["username"]); // cos
User u1 = User(); // class 와도 비슷함
User u2 = User();
}
단축키
control + / : 주석 해제 및 주석 설정
alt+enter : override method 작성
map, where (data를 다룰때 중요함)
void main(){
var c =["새우초밥", "광어초밥", "연어초밥"];
//map
var cChange = c.map((i)=> "간장_"+i).toList();
// map 은 반복되는 리스트를 변형해서 리턴해준다.
// 괄호안에 있는 i 가 각 리스트의 변수들이다.
// map 은 interable 타입으로 리턴해주기때문에 다시 리스트로
// 변환시켜주기 위해 .toList()를 해준다.
print(cChange);
//[간장_새우초밥, 간장_광어초밥, 간장_연어초밥]
//where
var cFind = c.where((i)=> i=="광어초밥").toList();
print(cFind);
//[광어초밥]
cFind = c.where((i)=> i!="광어초밥").toList();
print(cFind);
//[새우초밥, 연어초밥] // 광어초밥이 아닌 것만 배열에 담긴다.
// --> 배열에서 특정 원소를 삭제할 떄 자주 쓰인다.
}
스프레트 연산자
//스프레드 연산자 엄청나게 중요함
// 깊은 복사, 데이터추가 및 수정
// 활용도가 높은 코드이다.
void main() {
var list = [1,2,3];
//var newList = list; // 얕은복사 = 레버런스복사
var newList = [...list]; // 깊은복사 = 값을 복사
// 리스트가 그냥 정수일때는 스프레드를 사용하면 별도의 영향받지 않는 리스트 할당 가능
print(list);
print(newList);
list[0] = 10;
print(list);
print(newList);
//[1, 2, 3]
//[1, 2, 3]
//[10, 2, 3]
//[1, 2, 3]
---------------------------------------------------------
var list = [{"id":1}, {"id":2}];
var sublist = list; // 얕은 복사 -> 레퍼런스복사, 같은 주소값, 영향받음
var newList = list.map((i)=>{...i}).toList(); // 리스트가 오브젝트 형태일때는 스프레드를 사용해야 독립적인, 영향받지 않는 변수 생성가능
print(list);
print(newList);
print(sublist);
list[0]["id"] = 10;
print(list);
print(newList);
print(sublist);
print(list.hashCode);
print(newList.hashCode);
print(sublist.hashCode);
//---------------------------------------------------------
var users = [
{"id":1, "username":"cos", "password":1234},
{"id":2, "username":"ssar", "password":5678},
];
print(users);
// 중요!! 값 변경하여 저장하기
// ...i 뒤에 "username":"love"를 붙임으로써 덮어써버리는 것이다. => 스프레드 연산자를 이용하여 username만 수정 + 추가가 가능
var newUsers = users.map((i)=>i["id"]==2 ? {...i, "username":"love", "username2":"love"} : i);
print(newUsers);
//[{id: 1, username: cos, password: 1234}, {id: 2, username: ssar, password: 5678}]
//({id: 1, username: cos, password: 1234}, {id: 2, username: love, password: 5678, username2: love})
}
const, final 차이점
// const, final
// 공통점 : 값을 한번 설정하면 변경 불가
// 차이점
// final : 런타임시에 초기화되어야 한다. define시 값을 설정해줘야함.
// const : 컴파일시에 초기화되어야 한다.
class Dog{
final name;
const Dog(this.name);
}
void main(){
final n1;
const n2=2;
n1 = 3;
Dog a1 = const Dog("any");
Dog a2 = const Dog("any");
print(a1.hashCode);//928468236
print(a2.hashCode);//928468236
// const : 동일한 객체는 메모리를 공유한다.
}
Null safety
//방법1
class Person{
String? name;
int? age;
Person({this.name, this.age});
}
//방법2
class Person{
String name;
int age;
Person({required this.name, required this.age});
}
void main(){
Person p =Person(name: "홍길동", age: 19);
print(p.name);
print(p.age ?? 1);
}
/*
key값으로 접근하여 class를 생성하는 것이 직관적이고 보기 편하다.
-> 그러러면 선택적 매게변수를 써야 한다.
-> 이때 null값이 발생할 가능성이 있다.
-> null Sagefy로 인해 오류가 발생할 수 있다.
-> null 이 발생하지 않도록 안전하게 코딩하기 위해 도입되었다.
방법1
-> 때문에 String? 처럼 null 타입을 포함하도록 설정해야 한다.
방법2
-> 선택적 매게변수를 받을때 required 를 써서 무조건 넣도록 한다.
*/