Flutter에 대한 관심이 오래전부터 있었지만, 정작 공부를 시작하지는 못했습니다.
그래서 이번을 계기로 조금이나마 알아가보고자 Dart에 관한 공부를 결심했습니다.
저는 새로운 기술을 배울 때 노마드코더의 강의를 선호합니다. 노마드코더의 Dart 시작하기 강의를 선택했습니다.
노마드코더의 강의는 항상 흥미롭고 재밌습니다.👍
이 글을 통해, 강의를 듣고 공부한 내용을 정리해보려고 합니다.
Dart는 Flutter 앱 개발의 핵심 언어로, 뛰어난 성능과 효율성을 자랑합니다. 이 언어는 개발의 유연성과 신속성을 위해 두 가지 컴파일러 방식을 제공합니다.
- AOT (Ahead Of Time) 컴파일러: 이 컴파일러는 애플리케이션을 네이티브 코드로 변환하여 최적화된 바이너리를 생성합니다. 배포 시 활용되며, 모든 플랫폼에 맞추어 변환되기 때문에, 컴파일에 많은 시간이 걸립니다.
- JIT (Just In Time) 컴파일러: 개발 과정에서 빠른 반복 작업과 테스트를 가능하게 합니다. Dart VM에서 실행되며, 코드의 변경 사항을 실시간으로 반영하고 다양한 디버깅 옵션을 제공합니다.
모든 Dart 프로그램은 main
함수로 부터 시작합니다. 이 함수는 프로그램의 진입점으로서, Dart 컴파일러가 자동으로 찾아 실행합니다.
Dart에서 변수 선언은 var
키워드를 사용하여 이루어집니다. 타입 추론을 통해 Dart 컴파일러가 변수의 타입을 결정합니다.
명시적 타입 선언을 활용하면 코드의 가독성을 높일 수 있습니다. Dart 스타일 가이드에 따르면, 일반적으로 지역 변수에는 var
를 사용하고, 클래스 변수나 프로퍼티 선언에는 명시적 타입을 사용하는 것이 좋습니다.
Dart에서 변수 관리는 코드의 가독성과 안정성을 결정짓는 핵심 요소입니다.
final
키워드: 변수에 final
을 사용하면 해당 변수는 한 번만 값을 할당받을 수 있으며, 그 후에는 변경이 불가능합니다. 이는 변수의 불변성을 보장하며, 프로그램의 예측 가능성을 높여줍니다.
void main() {
final name = "pizza"; // 'name'은 한 번 할당 후 변경 불가
final String username = "tom"; // 명시적 타입과 함께 사용
}
late
키워드: 초기 데이터 없이 먼저 변수를 생성하고 추후에 데이터를 넣을 때 주로 사용한다. 이는 특히 비동기 작업 이후 값을 할당할 때 유용합니다.
void main() {
late final String name; // 초기화를 나중으로 미룸
}
const
키워드: 컴파일 시점에 값이 결정되는 상수를 정의할 때 const
를 사용합니다. const
로 선언된 변수는 프로그램 실행 동안 절대 변경되지 않습니다.
void main() {
const name = "tom"; // 컴파일 시점 상수
}
Null Safety: Dart에서 변수가 null 값을 가질 수 있는 경우, 해당 변수 타입 뒤에 ?
를 붙여야 합니다. 이는 해당 변수가 null 값을 가질 수 있음을 명확히 하며, 개발자가 의도치 않은 null 참조 오류를 예방할 수 있게 합니다.
void main() {
String? name = "jisoung"; // 'name'은 null 값을 가질 수 있음
name = null; // Null Safety로 인해 명시적으로 null 할당 가능
}
변수 참조: Dart에서는 $
기호를 사용하여 문자열 내에서 변수를 직접 참조할 수 있습니다. 복잡한 표현식의 경우 ${}
구문을 사용하여 계산할 수 있습니다.
void main() {
var name = "tom";
var age = 10;
var greeting = "hello $name, I'm ${age + 5}"; // 문자열 내 변수 사용
}
기본 데이터 타입: String
, bool
, int
, double
, num
등 Dart의 기본 타입들은 다양한 상황에서 데이터를 표현할 수 있게 해줍니다.
void main() {
String name = "tom";
bool isPlay = true;
int age = 10;
double money = 52.55;
num x = 12; // 정수와 실수 모두 가능
}
리스트와 컬렉션 연산: Dart의 리스트는 유연하게 데이터를 관리할 수 있는 구조를 제공합니다. collection if
와 collection for
는 조건에 따라 리스트를 동적으로 조작할 수 있는 기능입니다.
void main() {
var numbers = [1, 2, 3, 4, 5];
var dynamicList = [
'start',
if (true) 'middle', // 조건부 포함
for (var number in numbers) 'number $number', // 동적 요소 추가
'end',
];
}
Dart는 객체 지향 언어로, 함수도 객체입니다. 함수는 변수에 할당되거나 다른 함수의 인자로 전달될 수 있습니다.
String sayHello(String name) => "Hello $name, nice to meet you."; // 단축 구문 사용
num plus(num a, num b) => a + b; // 계산 결과 반환
void main() {
print(sayHello("sugar")); // 함수 호출
}
Named Parameters는 함수 호출 시 인자의 의미를 명확히 하여 가독성을 높입니다.
dart는 null safety로 인해 null을 막는 두가지 방법으로 사용할 수 있다.
default value
사용하여 해결할 수 있습니다.String sayHello({String name = 'anon',
int age = 99,
String country = 'wakanda',
}) {
return "Hello $name, you are $age, and you come from $country;
}
void main() {
print(sayHello()); // 아무것도 전달하지 않아도 default value가 이미 있으므로 null safety에 걸릴 일이 없음
}
required
사용하여 필수 매개변수를 지정할 수 있습니다.String sayHello({required String name, required int age, required String country}) {
return "$name / $age / $country";
}
void main() {
print(sayHello(name: "sugar", age: 10, country: "Korea"));
}
Dart에서 클래스를 정의할 때 프로퍼티는 타입과 함께 선언합니다. new
키워드는 선택적입니다.
class Player {
final String name = 'jisoung';
final int age = 17;
void sayName() {
print("Hi, my name is $name");
}
}
void main() {
var player = Player(); // 'new' 키워드 생략 가능
}
기본 생성자
Dart에서 클래스의 생성자는 클래스 이름과 동일해야 합니다. 생성자 내에서 this
키워드를 사용하여 인스턴스 변수를 초기화할 수 있습니다.
class Player {
late final String name;
late final int age;
Player(String name, int age) {
this.name = name;
this.age = age;
}
}
생성자 간소화
위 문법에서 Dart는 생성자 인자를 직접 인스턴스 변수에 할당하는 간소화한 문법을 제공합니다.
class Player {
final String name;
final int age;
Player(this.name, this.age);
}
Named Parameters를 이용한 생성자
클래스의 생성자에서 Named Parameters를 사용하면, 인자의 순서에 구애받지 않고, 각 인자의 역할이 명확해져 코드의 가독성이 향상됩니다.
class Team {
final String name;
final int age;
final String description;
Team({required this.name, required this.age, required this.description});
}
Named Constructor
Dart는 동일한 클래스 내에 여러 개의 Named Constructor를 정의할 수 있습니다.
class Player {
String name;
int xp;
String team;
Player.createBlue({required this.name, required this.xp, this.team = 'blue'});
Player.createRed({required this.name, required this.xp, this.team = 'red'});
}
Cascade Notation
Dart에서는 'cascade notation'(..
)을 사용하여 동일한 객체의 프로퍼티를 연속적으로 수정할 수 있습니다. 이는 코드를 간결하게 만들어 줍니다.
void main() {
var jisoung = Player(name: "jisoung", age: 17, description: "Happy coding is end coding")
..name = "nico"
..age = 20
..description = "Best project is end project";
}
enum
활용enum
은 한정된 값의 집합을 정의할 때 사용되며, 코드의 가독성과 안전성을 향상시킵니다.
enum Team {
red,
blue,
}
class Player {
String name;
int age;
Team team;
Player({
required this.name,
required this.age,
required this.team,
});
}
void main() {
var jisoung = Player(name: "jisoung", age: 17, team: Team.red);
var sushi = jisoung
..name = "sushi"
..age = 12
..team = Team.blue;
}
추상 클래스는 특정 메서드를 하위 클래스에서 구현하도록 요구하는 템플릿입니다.
abstract class Human {
void walk(); // 구현은 제공하지 않고 선언만 함
}
class Player extends Human {
void walk() {
print("Walking!"); // 'Human'을 상속받은 'Player'에서 'walk' 구현
}
}
여기서 Human
은 walk
메서드의 구현을 강제함으로써, 모든 하위 클래스가 일관된 인터페이스를 갖도록 합니다.
상속을 통해 클래스는 부모 클래스의 속성과 메서드를 재사용할 수 있으며, super
를 사용하여 부모 클래스의 생성자를 호출할 수 있습니다.
class Human {
final String name;
Human(this.name);
void sayHello() {
print("Hello! $name");
}
}
class Player extends Human {
String team;
Player({required this.team, required String name}) : super(name);
void sayHello() {
super.sayHello();
}
}
Player
클래스는 Human
클래스로부터 name
속성과 sayHello
메서드를 상속받습니다. @override
를 사용하여 sayHello
메서드를 재정의할 수 있습니다.
Mixin은 생성자를 갖지 않는 클래스로, 여러 클래스에 코드를 재사용하기 위해 사용됩니다.
mixin Tall {
final double height = 190.00;
}
class Human with Tall {
// 클래스 구현
}
Human
클래스는 Tall
Mixin을 with
키워드를 사용하여 포함시켜 height
속성을 재사용합니다. Mixin은 다중 상속의 혜택을 제공하며, 코드의 유연성과 재사용성을 높입니다.
Dart에서 abstract
, extends
, 및 Mixin
은 클래스 설계와 코드 구성에 핵심적인 역할을 합니다. 이들은 각각의 상황에 따라 코드의 재사용성, 확장성, 그리고 유연성을 개선하기 위해 사용됩니다.
키워드 | 적용 시기 | 사용 예시 |
---|---|---|
abstract | 하위 클래스에서 반드시 구현해야 하는 메서드를 정의할 때 사용합니다. | 게임 캐릭터의 공통 walk() 메서드를 Human 추상 클래스에 정의합니다. |
extends | 클래스가 다른 클래스의 속성 및 메서드를 상속 받아 재사용하려 할 때 사용합니다. | Player 클래스가 Human 클래스의 sayHello() 메서드와 name 속성을 상속 받습니다. |
Mixin | 재사용 가능한 기능을 여러 클래스에 추가하고 싶을 때 사용합니다. | Tall Mixin의 height 속성을 다양한 클래스에 적용합니다. |
이 기능들을 이해하고 활용함으로써 체계적이고 효율적인 프로그램을 개발할 수 있습니다.
Dart를 공부하며 새로운 시각으로 볼 수 있어서 흥미로웠습니다.
Dart에 대한 간략한 정리를 통해 기초를 다졌고, Flutter를 사용하면서 Dart의 심화 학습을 계속해 나갈 계획입니다.
감사합니다 😀
출처 :
https://nomadcoders.co/dart-for-beginners
https://dart.dev/guides