dart web dart로 쓴 코드를 js로 변환해주는 컴파일러
dart Native dart코드를 여러 cpu의 아키텍처에 맞게 변환시켜주는 컴파일러
dart는 두개의 컴파일러를 가지고 있다
JIT(just-in-time)
dart VM을 사용해서 코드의 결과를 바로 보여준다
개발중에만 사용하며 배포에는 사용하지 않는다
AOT(ahead-of-time)
컴파일을 먼저하고 그 결과인 바이너리를 배포하는 것으로 시스템에 맞게 최적화된 바이너를 생성하기 위해 컴파일에 많은 시간이 걸린다
최종 배포시 사용한다
ex) c++
main함수는 모든 dart 프로그램의 entry point이다
main함수에서 쓴 코드가 호출된다
dart는 자동으로 세미콜론을 붙여주지 않기 때문에 직접 붙여야한다( 일부러 세미콜론을 안 쓸 때가 있기 때문)
void main(){
print("hello world");
}
함수나 메소드 내부에 지역변수를 선언할 때는 var을 사용하고
class에서 변수나 property를 선언할 때는 타입을 지정해준다
데이터 타입이 일치하다면 변수는 업데이트 가능하다
void main(){
var name="pizza"; //방법1
String name="Chicken"; // 방법2
//방법1과 방법2는 같은 것
}
final
로 변수를 만들게 되면 이 변수는 수정할 수 없게 된다void main(){
final name="nico"
name="yeji" //로 수정불가능하다->에러발생
}
const: 컴파일 시점에 바뀌지 않는 값 (상수)
final: 컴파일 시점에 바뀌는 값, 런타임 중에 만들어질 수 있는 변수 (API에서 받아온 값, 사용자 입력값)
초기 데이터 없이 먼저 변수를 생성하고 추후에 데이터를 넣을 때 주로 사용한다.
flutter로 data fecthing을 할 때 유용하다.
late 변수를 만들고, API에 요청을 보낸 뒤에 API에서 값을 보내주면 그 응답값을 late변수에 넣어 사용할 수 있다.
void main() {
late final name;
print(name); // name 변수에 접근 불가
}
여러가지 타입을 가질 수 있는 변수에 쓰는 키워드이다(해당 변수의 타입을 알 수 없을 때 주로 사용)
변수를 선언할때 dynamic을 쓰거나 값을 지정하지 않으면 dynamic타입을 가진다
void main(){
var name //방법1
dynamic name // 방법2
//방법1과 방법2는 같은 것
}
null값을 참조할 수 없도록 하는 것
변수선언 뒤에 ?
를 붙여줌으로서 name이 string 또는 null이 될 수 있다고 명시해주는 것
기본적으로 모든 변수는 non-nullable(null이 될 수 없음)이다
void main() {
String? name = "hello";
name = null;
}
dart의 거의 대부분의 타입들이 객체로 이루어져있다
String, int, double, bool 모두 class이다
따라서 import할 필요 없이 해당 자료형이 가지는 모든 method를 사용할 수 있다
void main(){
String name = "tom";
bool isPlay = true;
int age = 10;
double money = 52.55;
num x = 12; //num은 그 값이 integer 일 수도 있고 double 일 수도 있다.
num y = 1.2;
}
dart에서 list를 선언하는 것에 두가지 방법이 있다
void main(){
var num=[1,2,3];
List num=[1,2,3];
}
dart의 유용한 점은 collection if
와 collection for
을 지원한다
void main() {
var giveMeFive = true;
List num = [1, 2, 3, 4, if (giveMeFive) 5]; //giveMeFive가 true면 5추가
print(num); //[1, 2, 3, 4, 5]
}
void main() {
var oldFriends = ["nico", "lynn"];
var newFriends = [
"tom",
"jon",
for (var friend in oldFriends) "❤️ $friend"
];
print(newFriends); // [tom, jon, ❤️ nico, ❤️ lynn]
}
$달러
기호를 붙이고 사용할 변수를 적어주면 된다.
만약 계산을 싱행하고 싶다면 ${ }
형태로 적어주면 된다.
void main() {
var name = "yeji";
var age = 10;
var greeting = "Hello everyone, my name is $name and I'm ${age + 2}";
}
key와 value를 연결하는 객체
키와 값 모두 모든 유형의 객체가 될 수 있다
void main() {
var player={
"name":"nico",
"xp":19.99,
"superpower":false
} //방법1
Map player={
"name":"nico",
"xp":19.99,
"superpower":false
} //방법2
}
set에 속한 모든 아이템들이 유니크해야될 때 사용한다
유니크할 필요가 없다면 list를 사용하면 된다
왜냐하면, list는 같은 요소가 여러개 반복될 수 있지만, set은 중복이 허용되지 않는다
void main() {
var numbers={1,2,3,4}; // 방법1. var을 사용
Set<int> numbers={1,2,3,4}; //방법2.자료형 명시
}
set에는 순서가 있다
print({1,2,3}=={3,2,1});
을 해보면 false가 나타난다
map
void main(){ var numbers=[1,2,3,4] numbers.add(1) numbers.add(1) print(numbers) //1,2,3,4,1,1 }
set
void main(){ var numbers={1,2,3,4} numbers.add(1) numbers.add(1) print(numbers) //1,2,3,4 }
dart는 진정한 객체지향언어이므로 함수도 객체이며 타입이 Function입니다
이는 함수를 변수에 할당하거나 다른 함수에 인수로 전달 할 수 있음을 의미합니다
//하나의 표현식만 포함하는 함수의 경우 아래와 같이 단축 구문을 사용할 수 있다
String sayHello(String name)=> "Hello ${name} nice to meet you";
void main(){
print(sayHello("yeji")); //Hello yeji nice to meet you"
}
void
함수가 아무것도 return하지 않는다는 의미
명시적으로 required로 표시되지 않는 한 선택사항
기본값을 제공하지 않거나 Named parameters를 필수로 표시하지 않으면 해당 유형은 기본값이 null이 되므로 null을 허용해야합니다
named parameter로 만들어주기 위해서는 함수의 파라미터를 중괄호로 감싸주면 된다
하지만 null-safety가 적용되어있기 때문에 default value를 지정해주거나 required키워드를 통해 반드시 값을 받도록 해주어야한다
String sayHello({String name = "yeji", int age = 20, String country = "ko"}) =>
"hello $name, you are $age, and you come from $country";
void main() {
print(sayHello(
name: "yeji",
country: "japan",
age: 27,
));
}
required을 사용하면 null safety를 적용할 수 있다.(required를 쓰면 값이 반드시 있어야 한다.)
String sayHello({
//디폴트 velue를 사용하는 방법
required String name,
required int age,
required String country
})=> "hello $name, you are $age, and you come from $country";
void main() {
print(sayHello(
name: "yeji",
country: "japan",
age: 27,
));
}
dart에서 []는 optional parameter를 명시할때 사용
String sayHello(
String name,
int age,
[String? country = "korea"],
) => return "Hello $name, age: $age, country $country";
void main(){
print(sayHello(
name: "jisoung",
age: 17,
);
}
??연산자
를 이용하면 null인지 체크해서 null이 아니면 왼쪽값을 리턴하고 null이면 오른쪽 값을 리턴한다
String capitalizeName(String?name)=>name?.toUpperCase() ?? "ANON"
??= 연산자
를 이용하면 변수안에 값이 null일때를 체크해서 값을 할당해줄 수 있다
void main() {
String? name;
name ??= "sugar"; //name이 null일때, sugar를 값으로 할당해준다
}
자료형에 사용자가 원하는 alias(자료형 이름의 별명을 만들때 사용)를 붙일 수 있게 해준다
typedef ListOfInts = List<int>;
ListOfInts reverseListOfNumbers(ListOfInts list) {
var reversedList = list.reversed.toList();
return reversedList;
}
class를 생성할 때는 타입을 명시해주어야한다
class Player {
String name = "nico";
int xp = 1500;
void sayHello() {
var name = "yeji";
print("hi! my name is $name"); // hi my name is yeji
print("hi my name is ${this.name}"); //hi my name is nico
}
}
void main() {
var player = Player(); //Player()를 호출하면 Player인스턴스가 생성된다
player.sayHello();
}
class내부 함수에서는 this로 변수값을 가져오지 않는다.
단, 함수내부에 같은 이름의 변수명이 있다면 this를 통해 명시해줘야한다
Named Constructor parameters
class Player {
String name;
int xp;
String team;
int age;
Player(
{required this.name,
required this.xp,
required this.team,
required this.age}); //constructors 생성방법
void sayHello() {
print("hi, my name is $name and i am $xp");
}
}
void main() {
var player = Player(name: "yeji", xp: 1300, team: "blue", age: 17);
var player2 = Player(name: "rak", xp: 1600, team: "pink", age: 21);
player.sayHello();
player2.sayHello();
}
생성자(constructor)함수를 여러개 만들고 싶다면 어떨까?
콜론(:)을 사용하면 특별한 생성자 함수를 만들 수 있다
콘론을 넣음으로서 dart에게 여기서 객체를 초기화하라고 명령할 수 있다
class Player {
final String name;
int xp;
String team;
Player.fromJson(Map<String, dynamic> playerJson)
: name = playerJson["name"],
xp = playerJson["xp"],
team = playerJson["team"];
void sayHello() {
print("hello my name is $name");
}
}
void main() {
var apiData = [
{
"name": "yeji",
"team": "red",
"xp": 0,
},
{
"name": "rak",
"team": "red",
"xp": 0,
},
{
"name": "nico",
"team": "red",
"xp": 0,
}
];
apiData.forEach((playerJson) {
var player = Player.fromJson(playerJson);
player.sayHello();
});
}
class Player {
String name;
int xp;
String team;
Player({required this.name, required this.xp, required this.team});
void sayHello() {
print("hello my name is $name");
}
}
void main() {
var yeji = Player(name: "yeji", xp: 1200, team: "red")
..name = "las" //...은 yeji.name와 같다
..xp = 1200000 //...은 yeji.xp와 같다
..team = "blue" ////...은 yeji.team과 같다
..sayHello(); // hello my name is las
}
enum은 우리가 실수하지 않도록 도와주는 타입이다
enum Team{red, blue}
enum XPLevel{beginner,medium, pro}
class Player {
Team team;
XPLevel xp
Player({required this.team, required this.xp});
}
void main() {
var yeji = Player(team: Team.red); //enum을 사용해서 실수를 줄이는 방법
}
추성화 클래스는 이를 상속받는 모든 클래스가 가지고있어야 하는 메소드를 정의하고 있다
추상화 클래스에서는 기능을 구현하지 않는다
extends를 이용해 상속,확장을 할 수 있다
abstract class Human {
void walk();
}
class Player extends Human {
void walk() {
print("im walking");
}
}
class Coach extends Human {
void walk() {
print("the coach is walking");
}
}
super라는 키워드를 통해 확장을 한 부모클래스와 상호작용할 수 있게 해준다
즉, 상속한 부모 클래스의 프로퍼티에 접근하게 하거나 메소드를 호출할 수 있게 해준다
@override를 이용해 부모 클래스의 객체를 받아올 수 있다.
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);
// super를 통해 부모클래스와 상호작용할 수 있게해준다
void sayHello(){
super.sayHello(); //Human의 print("Hello! $name")을 불러온다
}
}
Mixin은 생성자가 없는 클래스를 의미한다
Mixin클래스는 상속을 할때 extend를 하지 않고 with를 사용한다
Mixin의 핵심은 여러 클래스에 재사용이 가능하다
mixin과 extends의 차이점은요??
extends를 하게되면 확장한 그 클래스는 부모 클래스가 되지만 with는 부모의 인스턴스 관계가 된다
단순히 mixin 내부의 프로퍼티를 갖고 오는것
mixin Strong {
final double strength = 1500.0;
}
mixin QuickRunner {
void runQuick() {
print("runnnnn!");
}
}
enum Team { blue, red }
class Player with Strong, QuickRunner {
final Team team;
Player({required this.team});
}
void main() {
var player = Player(team: Team.red);
}