반응형
이 글은 Nomad Coders님의 Dart 문법 강의를 복습을 위해 요약한 것입니다.
해당 강의는 가입하면 무료로 제공되는 강의라 누구나 쉽게 들을 수 있습니다.
https://nomadcoders.co/dart-for-beginners
Flutter의 언어인 dart에 대해 설명이 상세히 잘 되어 있었습니다.
확실히 Nomad Coders님이 강의를 잘해...
void main() {
print("hello world");
}
- 끝에 세미콜론 찍고 처음 시작코드는 다른 문법과 마찬가지로 무조건 void main(){ }에서 시작을 한다.
1. 변수
var
var name ='니꼬';
name = 3;//(x)
name = '3';//(o)
string name='니꼬';
- var을 사용할 경우 dart 컴파일러가 자동으로 자료형 맞춰준다.
- 그 대신 처음에 선언한 변수의 자료형과 다르면 수정이 되지 않고, 처음 자료형에만 맞추어져 정해진다.
- 꼭 var을 사용하지 않고 명시적으로 변수 타입을 지정해 주는 것도 가능하다.
- 내부 지역변수를 사용할 때는 굳이 지정 안 해도 알아서 처리하니 var을 써도 좋다.
- 하지만 큰 단위로 쓰는 변수는 명확히 할 필요가 있으니 자료형을 지정해 주는 것이 좋다고 한다.
dynamic
dynamic name;
name =12;
name =true;
name = 'nico';
if(name is string){
//여기서는 name이 string일때를 상정해 자동완성해줌
}
- var로 선언하고 값을 넣지 않거나 dynamic으로 선언하면 어떤 자료형이 들어가도 그에 맞춰 변환해 괜찮은 상태가 됨. 이를 dynamic이라고 한다.
- var과 마찬가지로 자료형이 유동적으로 변하나, var은 처음에 지정된 자료형에 맞추는 것이었다. dynamic은 매번 새로운 자료형에 맞춘다.
- 커서를 올려서 현재 자료형을 확인하거나 온점을 찍고 자동완성되는 것을 보고 dynamic 중에서도 현재 어떤 자료형으로 인식하고 있는지 알 수 있다.
- dart내부에는 그 변수가 비었는지, 홀수짝수인지 무한인지 음수인지 등등 다양한 내부판별 속성을 가지고 있다. 유용하게 쓸 수 있을 것이다.
- dynamic은 필요할 때만 써야 한다. 남용하면 자료형끼리 꼬인다.
nullable
string nico = 'a'
string? nico2 = 'a'
nico = null;//(error)
nico2 = null;//(correct)
nico2?.isNotEmpty;
- null safety란 어떤 변수나 데이터가 null이 될 수 있음을 명시하는 것을 말한다.
- dart에서 기본적으로 모든 자료형은 기본적으로 null이 불가다. 즉 null이 들어갈 수 없다. null이 들어가면 미리 컴파일 전에 error를 띄운다.
- 하지만 자료형 뒤에 ‘?’를 붙인다면 null 값도 들어갈 수 있게 된다.
- 코드 중간에 null인지 아닌지 확인하고 집어넣으려면 변수뒤에?를 붙인 후 처리해 주면 된다.
final
final name = 'nico'
final string name2 = 'adf'
name = 'dsf' // error
name2 = 'ad' //error
- final로 선언한 변수는 다른 언어의 const로 선언한 변수처럼 한번 선언하면 바꿀 수 없다.
- final과 변수 명 사이에 자료형을 명시해주어도 되고 안 해주어도 된다. 컴파일러가 알아서 자료형을 인식하기에 큰 상관없다.
late
late final String name;
print(name); // error
name='nico';
print(name); //correct
- late는 변수 선언 시 데이터 값을 미리 집어넣지 않고 나중에 값을 넣을 수 있게 해 준다
- null 값으로 인식하고 함수에서 그냥 처리해 버리는 것을 컴파일 전에 막는다
- 나중에 다른 클래스에서 쓸 때 유용하게 쓰인다.
const
const ap = 'd'; //correct
const ap = 'c' //error
const api = fechApi(); //error
- dart에서 const는 자바스크립트 같은 곳의 const와는 다르다. 오히려 그것들은 final과 유사하다.
- const는 final처럼 수정불가다. 다만 중요한 건 const는 이미 그 값을 컴파일 전에 알고 있어야 한다.
- 즉, 하드코딩 된 값이든 뭐든 미리 알고 있어야 하며, api나 다른 함수에서 받아오거나, 사용자가 입력해서 들어가는 값이라거나 이런 식으로 컴파일 전에 모르는 값이면 들어갈 수 없다. 상수가 되는 것이다.
2. 자료구조
기본 자료구조
String name = "gg";
String name2 = 'ff';
bool alive = true;
int age =12;
double money =69.99;
num x =12;
x = 1.1;
- String 자료형은 따옴표 큰따옴표 상관없다. 둘 다 된다.
- String 선언할 때는 다른 자료형과 달리 첫 글자를 대문자로 써야 한다.
- string, bool, int, double 등 기존에 익숙하던 자료형을 사용하면 된다.
- 모든 자료형이 object형태로 이루어져 있기에 변수 뒤에 온점 찍으면 다양한 기능 사용 가능하다.
- num은 숫자면 다 되는 자료형으로 int와 double, 즉 소수점이 있든 없든 사용 가능하다.
리스트
var givemefive = 5;
var numbers = [1,2,3,4]; // 자동으로 이게 리스트로 선언됨
List<int> numberss = [1,2,3,4,if(givemefive) 5]; //이렇게 선언할 수도 있음
numberss.add("dsf"); //자료형 맞지 않으므로 error
numbers.first;//첫번째 원소 가져옴
numbers.last;//마지막 원소 가져옴
print(numberss);//1,2,3,4,5
- 대괄호와 요소들 사이 쉼표로 선언하고, List <자료형> 자료명 =[요소 1, 요소 2…] 형태로 선언할 수도 있다.
- 리스트 자료형도 상속형태로 이루어져 있어서 온점 찍으면 다양한 기능 쓸 수 있다.
- 팁으로 dartpad나 vscode 쓸 때 리스트 선언 후 맨 마지막 요소 뒤에도 쉼표를 붙여주면 리스트 요소별로 행구별이 되어 가독성이 좋아진다.
- dart의 list는 혁신적인 기능이 있는데 collection if 문이 있다는 것이다. 리스트 안에 if문을 넣어 원소를 넣을지 말지 정할 수 있다.
문자열 보간법
var name = 'mico';
var age = 10;
var greeting = 'my name is $name , nice to meet you. I\\'m ${age +2}';
print(greeting); //my name is mico , nice to meet you. I'm 12
- 변수를 선언할 때 포맷팅으로 다른 변수 값을 가져와 저장하는 것이 가능하다. 그냥 선언할 때 포맷팅 원하는 변수 앞에 $를 붙이기만 하면 된다.
- 위의 것은 문자열과 같은 단순 변수를 혼합할 때의 이야기이고 숫자를 담아와서 계산해 포맷팅 하고 싶다면 ${변수와 그 식}을 적어주면 자동으로 계산해 할당된다.
- 문자열 선언 중 달러나 따옴표를 출력하고 싶다면 앞에 이스케이프 코드 '\'를 넣어준다.
리스트 안의 for
var oldfrineds = ['nico','lynn'];
var newfriends = ['tom', 'jay', for(var friend in oldfriends) "love $friend "];
print(newfriends); //[tom, jay, love nico, love lynn]
- 리스트 안에 for문을 넣어 for문으로 원소들을 할당할 수 있다.
- 가령 for(var 변수명 in 이미 선언한 리스트) “포맷팅 하고 싶은 문구를 채워 넣으세요 $변수명” 같은 방식으로 쓴다. 이미 선언한 변숫값을 포맷팅 해 새로운 리스트에다가 다채로운 형태로 할당할 수 있는 것이다.
맵
var me ={
'name': 'jun',
'xp': 5,
'power' :false,
}
me['study'] = 'hard';
Map<List<int>, bool> player={[1,2,3,5] :true};
List<Map<String, Object>> players = [{'name': 'nico', 'xp': 99999},
{'name': 'jun', 'xp': 1}];
- map은 자바스크립트의 오브젝트나 파이썬의 딕셔너리 같은 것으로 key:value값을 가진다.
- 위와 같은 방식들로 map을 선언할 수 있다.
- 보면 다양한 자료형을 가진 value 값을 커서를 올렸을 때 컴파일러는 object로 인식하는데 이는 뭐든 지 올 수 있는 any와 같은 뜻이다.
- 컴파일러가 키나 value값의 자료형이 계속 달라도 알아서 object로 인식한다는 뜻이다.
- 맵도 마찬가지로 온점 찍으면 다양한 메서드를 사용할 수 있다.
- api나 영화 음악등을 담은 특정 형태와 의미를 가진 데이터를 다룰 때에는 map보다는 class 사용을 권장한다.
세트
var numbers= {1,2,3};
Set<int> numberss = {1,2};
numbers.add(1); //무효화
- set는 위와 같은 형태들로 중괄호를 이용해 선언할 수 있다. (리스트는 대괄호다)
- set에는 중복된 원소가 들어갈 수 없다. 중복된 원소는 아무리 추가해도 한 번만 나온다.
- 그러니 요소가 항상 하나씩만 있어야 하면 set, 그럴 필요가 없다면 list를 쓴다
- 이는 파이썬의 tuple과 같다.(파이썬의 리스트는 다트의 리스트와 같다.)
함수 선언
함수 정의
void sayhello(String name){
print("hello $name");
}
String sayhello2(String name) => "hi $name";
sayhello("jun"); // hello jun
print(sayhello2("jun"))//hi jun
- 함수 선언은 간편한 다른 언어의 함수 선언과 비슷하다. 앞에 return 될 자료형 함수명(인자자료형 변수명) {}로 선언한다.
- 중괄호와 리턴값을 생략하고 화살표 문법을 이용해 자바스크립트 화살표 식이나 파이썬 람다처럼 간편하게 함숫값을 곧바로 출력할 수도 있다.
이름기반 파라미터
String sayHello({required String name,int age = 10,required String country}) => return "Hello $name, age: $age, country $country";
//named parameter를 사용하기 위해 중괄호로 감싼 모습이다.
//null safety를 위해 required로 인자가 안오면 컷하거나 미리 default 값을 지정해줄 수 있다.
void main(){
print(sayHello("jisoung", 17, "korea"));//보기 불편하다.
print(sayHello({
name: "jisoung",
age: 17,
country: "korea",
});
// 다음과 같이 바꿀 수 있다. 변수명을 명시 해주는 것이다.
}
- 파라미터가 다양하게 들어갈 경우, 순서를 일일이 기억해 인자들을 순서대로 입력하는 것은 비효율 적이다.
- 그래서 파라미터 명: 들어갈 값으로 순서 상관없이 대입할 수 있다.
- 위 과정을 사용할 때 자동완성으로 편하게 할 수 있다.
- 하지만 그렇게 명시된 파라미터를 사용하기 위해서는 파라미터의 소괄호 안에 중괄호{}를 사용해야 하며, 일부만 명시된 변수를 사용하는 것이 아닌 모두 명시된 파라미터를 사용해야 한다. 일부는 그냥 대입하는 건 안된다.
- 함수의 파라미터에 = 자를 이용해 아무것도 들어오지 않았을 때 null로 왔을 때 default 값을 선언해 줄 수 있다.
- default를 이용하고 싶지 않다면, 변수의 자료형 앞에 required를 적어주면 무조건 값을 할당해야 한다는 것을 알기에 nullsafety 하게 쓸 수 있다.
요약
- 위치로 값만 표시하는 positional parameter과 자료형까지 명시해 순서가 아닌 파라미터 이름으로 호출하는 named parameter. 파라미터가 많을수록(3개 이상일 때) named parameter를 쓰는 게 좋다.
- 파라미터를 누락해 호출시킬 경우 null 에러가 발생하기 때문에 required를 쓰거나 default 값을 정해준다.
선택적 위치기반 파라미터
int plus (int a, [int? b = 5]) => a+b;
print(plus(3)); // 8
- 함수를 호출할 때 경우에 따라 모든 파라미터를 사용하지 않기를 바랄 수도 있다. 그러면 위치기반으로 파라미터 여러 개를 받는다면 어떻게 해야 할까?
- 함수 쪽 파라미터 자료형 뒤에?를 붙여 null일수도 표시한 후 =으로 default 값을 정해준다. 그리고 그 파라미터를 대괄호로 감싼다. 그러면 해당 파라미터를 입력하지 않았을 때도 default 값으로 정상적으로 출력된다.
물음표 오퍼레이터
- a?? b는 a가 null이면 b를 출력한다. null이 아니라면 그대로 a를 출력한다.
- a??= b는 a가 null이면 자동으로 b를 할당한다.
타입정의
typedef loi = List<int>;
loi reversenumber(loi list){
var rebersed = list.reversed;
return reversed.toList();
}
print(reversenumber([1,2,3])); //3,2,1
- 자료형만으로 길어질 때 그 자료형의 이름을 typedef를 통해 이름을 붙여 사용할 수 있다. 이를 alias라고 한다.
- 하지만 구조화된 자료형을 제대로 만들고 싶다면 class를 사용하는 게 좋다.
클래스
클래스
class Player{
final String name = 'nico';
int xp = 1500;
void sayHello(){
print($name);
}
}
var player = Player();
player.name = 'jun';//error
- 플러터에서 클래스는 매우 매우 중요하다.
- 새로운 클래스를 선언할 때 new 없이 그냥 선언해도 된다.
- 클래스 내부 변수를 사용할 때 this. 를 붙이지 않는 걸 권고한다.
- 클래스 내부 변수에서 final로 선언하면 당연히 바꿀 수 없다.
구조체
class Player{
final String name;
int xp;
Player(this.name, this,xp);//생성자 함수로 줄일 수 있음
void sayHello(){
print("Hi my name is $name");
}
var player = Player("nico",1500);
player.sayHello(); //Hi my name is nico
var player2 = Player("lynn",2500);
player2.sayHello(); //Hi my name is lynn
- 신규 클래스 구조체를 생성하는 방법이다.
- 입력한 값이 property 값으로 this를 이용한다면 굳이 따른 줄로 할당할 필요가 없다.
- 구조체 명과 같은 이름을 쓰고 괄호 안에 this를 넣으면 된다.
- 즉 신규 클래스 생성을 줄일 수 있는 것이다.
- 그 대신 위치기반 파라미터를 사용할 때처럼 순서를 맞추어야 된다.
이름기반 구조체 파라미터
class Player{
final String name;
int xp;
Player({
required this.name,
required this,xp,;//생성자 함수로 줄일 수 있음
});
var player = Player(
name:"nico",
xp:1500,);
- 함수에서 위치기반 파라미터를 생성할 때, 파라미터가 많아지면 불편했던 것처럼 신규 구조체 생성에도 순서 상관없이 이름기반 방식을 사용할 수 있다.
- 이름기반을 써야 하니 새로 생성하는 부분에 중괄호{}를 넣어준다.
- 마찬가지로 인수가 null일 때 들어오지 않을 때를 대비해 required를 쓰든 default를 주든 해주면 된다.
- 이런 형태를 더 많이 사용하게 될 것이다.
이름기반 구조체
class Player{
final String name;
int xp,age;
String team;
Player.createBlue({
required String name,
required int age,
}) :this.name = name,
this.age = age;
this.xp = 0,
this.team = 'blue';
Player.createRed(String name, int age) :
this.age = age,
this.name = name,
this.team = 'red',
this.xp=0;
}
var player = Player.createBlue(
name:"nico",
age:12,);
var player = Player.createRed("nico",12);
- 변수 한 번에 생성 가능해서 줄 절약 가능하다.
- 구조체 안에서 새로운 구조체를 만들어서 새로운 구조체만 사용할 수 있다.
- 콜론: 을 통해 새로 만든 구조체 안의 구조체 값을 초기화할 수 있다.
- 여기서도 마찬가지로 named와 positional 파라미터 방식 2가지를 쓸 수 있다.
- 매서드 안에서 새로운 매서드를 만드는 것이다.
중간요약
class Player{
final String name;
int xp;
String team;
Player.fromJson(Map<String, dynamic> playerJson):
name = playerJson['name'],
xp = playerJson['xp'],
team = playerJson['team'];
}
var apidata= [
{
"name":"nico",
"team":"red",
"xp":0,
},
{
"name":"jun",
"team":"red",
"xp":0,
}
];
apidata.forEach((playerJson){
var player= Player.fromJson(playerJson);
}
캐스케이드 기호
var player = Player("nico",1500)
..name = 'las'
..sayHello()
- 구조체를 만들고 그 구조체의 함수나 인자를 불러와 변경 등을 할 때는 가장 최근에 선언한 클래스 뒤의 세미콜론;을 없애고 인자의 이름 대신..으로 편하게 작성할 수 있다.
enum
enum Team { red, blue}
team: Team.red;
team Team.blue;
- enum은 어떤 값이 가질 수 있는 리스트들을 만들어 놓고 그 안에서 선택할 수 있는 우리가 만드는 객관식 선지들이다.
- enum은 하드코딩에서 오타로 인한 실수를 줄여주는 역할을 한다.
- 문자열이든 아니든 상관없다.
추상화 매서드
abstract class Human{
void walk();
}
class Player extends Human{
void walk(){
print('walking');
}
}
- 추상화 클래스는 다른 클래스들이 직접 구현해야 하는 메서드를 모아놓은 일종의 청사진이다.
- 새로 만든 클래스에 extends를 통해 상속하고 확장할 수 있다.
- 추상 클래스 안에는 메서드의 이름과 반환값 void 같은 것만 설정하고 내부 함수들은 쓰지 않는다.
- 즉, 추상화 메서드는 특정 구조체 안에 특정 메서드가 들어가야 함을 강제하고, 그 메서드들은 구조마다 다르게 설정할 수 있는 것이다.
상속
class Human {
final String name;
Human(this.name); // 호출 받는다.
void sayHello(){
print("Hello! $name");
}
}
class Player extends Human {
Player({
required this.team,
required String name
}) : super(name: name);
// Human의 생성자 함수를 호출한다.
}
@override
void sayHello(){
suoer.sayHello();
print("hahaha");
}
var player = Player(team: Team.red ,name:"nico");
- super 키워드를 통해 확장을 한 부모클래스의 생성자를 호출할 수 있다.
- override 키워드로 상속받은 함수를 커스터마이징 한 다른 것으로 교체한다.
mixin
class Strong{
final int power = 999;
}
class QuickRunner{
print("runnnnn");
}
class Player with Strong, QuickRunner{
}
- mixin은 생성자가 없는 클래스를 말한다
- mixin은 클래스 여러 개를 동시에 받을 수 있다. 부모클래스가 되는 게 아니라 그냥 뺐어 오는 것이다. 그 대신 생성자가 없어야 한다.
- 해당 클래스 옆에 with으로 프로퍼티를 연결할 수 있다.
- 현재는 앞에 mixin 키워드를 붙여야지 정상적으로 사용할 수 있다.
내용이 연계되는 다음 글!
2024.01.10 - [개발] - [Nomad Coders] Flutter로 UI 만들기
반응형
'개발 > 클론코딩' 카테고리의 다른 글
[Nomad Coders] Flutter로 Pomodoros 앱 만들기 (1) | 2024.01.10 |
---|---|
[Nomad Coders] Flutter로 UI 만들기 (2) | 2024.01.10 |
JavaScript로 테트리스 만들기, 코린이가 코린이를 위한 A-Z 설명 4 (完) (0) | 2023.05.08 |
JavaScript로 테트리스 만들기, 코린이가 코린이를 위한 A-Z 설명 3 (0) | 2023.04.29 |
JavaScript로 테트리스 만들기, 코린이가 코린이를 위한 A-Z 설명 2 (0) | 2023.04.22 |