- 시작하며 -
Flutter를 사용하기에 앞서 Flutter가 사용하는 언어인 Dart에 대해서 알아봅시다.
다트(Dart)는 구글이 디자인한 멀티 플랫폼 프로그래밍 언어이다. 이는 2011년 10월 10일~12일까지 열렸던 "GOTO 콘퍼런스"에서 공개되었다. 다트는 자바스크립트를 대체가능하며 크로스 플랫폼 프로그래밍 언어를 목표로 설계되었다.
출처 : 위키피디아
이처럼 Flutter의 언어인 Dart는 구글의 안드로이드 OS와 애플사의 IOS에서의 하이브리드 앱을 재작 하기 위해서 구글에서 고안한 언어입니다. 또한 Dart는 기본적으로 C언어의 문법과 거의 같으며 Java, C#, Javascript와 같은 기능적 스트럭처를 추가한 언어로, 언급된 언어보다 간결하고 강력한 기능을 지원합니다
- 본문 -
다트는 위링크에서 손쉽게 돌려볼 수 있습니다.
기본규칙
main 함수
main() {
}
다른 언어들과 비슷하게 Dart는 main 함수에서 돌아갑니다
주석
//한줄 주석
/*
* 여러줄 주석
*/
///문서 주석
주석 또한 다른 언어들과 비슷한 점을 가지고는 있지만 /// 이주석 같은 경우 문서 주석으로 dartdoc와 같은 문서 생성 도구를 통해 문서를 자동으로 생성해 줍니다.
출력, 세미콜론(;)
print("Hello Dart");
출력함수의 경우 다른 언어들처럼 print함수를 통해 Console에 값을 출력할 수 있습니다.
다트는 C나 Java처럼 문장의 마지막 세미콜론을 찍어 컴파일러에게 여기가 문장의 마지막이라는 것을 알려줍니다.
메서드의 리턴 타입
add(){
return 3+2;
}
main(){
int sum = add();
print(add());
}
메서든 리턴타입을 추론할 수 있기 때문에 생략이 가능합니다.
1급 객체
Dart의 경우 변수, 함수, 객체를 포함한 모든 것이 1급 객체입니다. 그렇기 때문에 new라는 키워드가 필요 없으며 메모리에 자동으로 올라가기 때문에 바로 사용할 수 있습니다.
변수와 상수
변수와 상수
타입추론이 가능한 변수
var이나 final, const 같은 경우 해당값이 주어진다면 그 값에 맞는 타입을 추론하여 변수의 타입을 지정할 수 있습니다.
변수 | var | 값을 변경할수있는 변수입니다. |
상수 | final | 실행중에 값이 결정됩니다. 값을 변경할수 없는 상수입니다. |
const | 컴파일시에 값이 결정됩니다. 값을 변경할수 없는 상수입니다. |
//var
var age = 25;
var name = 'John';
var isStudent = true;
//final
final int age = 25;
final String name = 'John';
final bool isStudent = true;
//const
const int age = 25;
const String name = 'John';
const bool isStudent = true;
이렇게 타입을 추론하는 변수 말고도 자료형을 사용하여 변수를 선언할 수도 있습니다.
자료형 | 설명 |
String | 단따옴표와 쌍따옴표로 이루어진 문자열 , 참고로 Dart 에서는 문자는 String으로 표현 |
int | 정수(다른언어처럼 short 난 long이없고 int 로 정수 전채를 표형함) |
double | 실수(위 int와 비슷한이유로 float가없다) |
bool | 참(True) 또는 거짓(False) 값을 가지는 자료형입니다. |
List<T> | 순서가 있는 항목의 목록을 나타내는 자료형입니다. 대괄호([])로 둘러싸인 요소의 목록을 사용하여 리스트를 생성할 수 있습니다. |
Map<K, V> | 키와 값의 쌍으로 이루어진 데이터의 집합을 나타내는 자료형입니다. 중괄호({})로 둘러싸인 키-값 쌍의 목록을 사용하여 맵을 생성할 수 있습니다. |
dynamic | 동적 타입을 나타내는 특수한 자료형입니다. 변수가 동적 타입을 가지면 컴파일러는 해당 변수의 타입을 추론하지 않고 런타임에 타입을 결정합니다. |
//String
String name = "John";
String message = 'Hello, Dart!';
String concatenated = name + ' says ' + message;
//int
int age = 25;
int quantity = 10;
int result = age * quantity;
//double
double pi = 3.14;
double radius = 2.5;
double area = pi * radius * radius;
//bool
bool isRaining = true;
bool isSunny = false;
bool isCloudy = !isRaining;
//List<T>
List<int> numbers = [1, 2, 3, 4, 5];
List<String> names = ['Alice', 'Bob', 'Charlie'];
List<dynamic> mixed = [1, 'two', true];
//Map<K, V>
Map<String, int> ages = {'Alice': 25, 'Bob': 30, 'Charlie': 35};
Map<String, dynamic> person = {'name': 'John', 'age': 40, 'isStudent': false};
//dynamic
dynamic value1 = 10;
dynamic value2 = 'Hello';
dynamic value3 = true;
Nullable
Dart에서도 Kotlin처럼 nullable 처리를 할 수 있습니다. Nullable 타입을 사용하려면 변수의 타입 뒤에?를 붙입니다. 이를 통해 해당 변수가 null을 가질 수 있음을 표시합니다.
int? nullableValue = null;
String? nullableString = 'Hello';
널 처리의 경우 Kotlin과 매우 유사합니다
Dart | Kotlin | 설명 | |
널 체크 연산자 | ! | !! | Nullable 타입의 변수를 사용할 때 변수가 null이 아님을 명시적으로 표시할때 사용합니다. |
조건부 접근 연산자 | ?. | ?. | Nullable 타입의 변수를 사용할 때 변수가 null이 아닌 경우에만 접근하려는 경우에 사용합니다. |
널 병합 연산자 | ?? | ?: | Nullable 타입의 변수가 null일 때 대체 값을 지정하여야하는 경우 사용합니다. |
int? nullableValue = null;
String? nullableString = 'Hello';
//------------------------------------------------
int? nullableValue = 5;
int nonNullableResult = nullableValue!; // nullableValue는 null이 아님을 보장
//------------------------------------------------
String? nullableString = 'Hello';
int? stringLength = nullableString?.length; // nullableString이 null이면 stringLength도 null
//------------------------------------------------
String? nullableString = null;
String nonNullableString = nullableString ?? 'Default Value'; // nullableString이 null이면 'Default Value' 할당
연산자
산술 연산자 | + | 덧셈 연산을 수행합니다. |
- | 뺄셈 연산을 수행합니다. | |
* | 곱셈 연산을 수행합니다. | |
/ | 나눗셈 연산을 수행하고 결과를 부동 소수점으로 반환합니다. | |
% | 나머지 연산을 수행합니다. | |
할당 연산자 | = | 우변의 값을 좌변에 할당합니다. |
+=, -=, *=, /=, %= | 우변의 값을 좌변의 값과 함께 연산하여 결과를 좌변에 할당합니다. | |
증감 연산자 | ++ | 피연산자의 값을 1 증가시킵니다. |
-- | 피연산자의 값을 1 감소시킵니다. | |
비트 연산자 | 비트 왼쪽 시프트 연산자 << |
왼쪽 피연산자의 비트를 오른쪽 피연산자만큼 왼쪽으로 이동시킵니다. 이동된 비트는 왼쪽에서부터 0으로 채워집니다. |
비트 오른쪽 시프트 연산자 >> |
왼쪽 피연산자의 비트를 오른쪽 피연산자만큼 오른쪽으로 이동시킵니다. 이동된 비트는 부호 비트(최상위 비트)와 동일한 값으로 채워집니다. | |
비교 연산자 | == | 두 값이 같은지 비교합니다. |
!= | 두 값이 다른지 비교합니다. | |
>, <, >=, <= | 크기 비교를 수행합니다. | |
논리 연산자 | && | 논리 AND 연산을 수행합니다. |
|| | 논리 OR 연산을 수행합니다. | |
! | 논리 NOT 연산을 수행합니다. | |
조건부 연산자 | ? | 조건식의 참/거짓에 따라 값을 선택합니다. |
타입 확인 및 캐스트 연산자 | is | 객체의 타입을 확인합니다. |
as | 객체를 지정된 타입으로 변환합니다. | |
멤버십 연산자 | in | 특정 요소가 컬렉션(리스트, 맵 등)에 속하는지를 확인하는 데 사용됩니다 |
// 산술 연산자
int sum = 10 + 5; // 15
int difference = 10 - 5; // 5
int product = 10 * 5; // 50
double quotient = 10 / 5; // 2.0
int remainder = 10 % 3; // 1
// 할당 연산자
int num1 = 10;
num1 += 5; // num1 = num1 + 5; // 15
num1 -= 3; // num1 = num1 - 3; // 12
num1 *= 2; // num1 = num1 * 2; // 24
num1 /= 4; // num1 = num1 / 4; // 6.0
num1 %= 4; // num1 = num1 % 4; // 2
// 증감 연산자
int num2 = 5;
num2++; // num2 = num2 + 1; // 6
num2--; // num2 = num2 - 1; // 5
// 비트 연산자:
int a = 5; // 이진수: 0000 0101
int b = 3; // 이진수: 0000 0011
int bitwiseAnd = a & b; // 비트 AND 연산: 0000 0001 (1)
int bitwiseOr = a | b; // 비트 OR 연산: 0000 0111 (7)
int bitwiseXor = a ^ b; // 비트 XOR 연산: 0000 0110 (6)
int bitwiseNotA = ~a; // 비트 NOT 연산: 1111 1010 (-6)
int leftShift = a << 2; // 비트 왼쪽 시프트 연산: 0001 0100 (20)
int rightShift = a >> 1; // 비트 오른쪽 시프트 연산: 0000 0010 (2)
// 비교 연산자
int num3 = 10;
int num4 = 5;
bool isEqual = (num3 == num4); // false
bool isNotEqual = (num3 != num4); // true
bool isGreater = (num3 > num4); // true
bool isLess = (num3 < num4); // false
bool isGreaterOrEqual = (num3 >= num4); // true
bool isLessOrEqual = (num3 <= num4); // false
// 논리 연산자
bool condition3 = true;
bool condition4 = false;
bool andResult = (condition3 && condition4); // false
bool orResult = (condition3 || condition4); // true
bool notResult = !condition3; // false
// 멤버십 연산자
List<int> numbers = [1, 2, 3, 4, 5];
bool isPresent = 3 in numbers; // true
bool isMissing = 6 in numbers; // false
흐름제어문
조건문
if, else if, else 문, switch문, 3항 연산자 => 자바의 조건문과 같음
if (condition1) {
// condition1이 참일 때 실행될 코드
} else if (condition2) {
// condition1이 거짓이고 condition2가 참일 때 실행될 코드
} else {
// 모든 조건이 거짓일 때 실행될 코드
}
//-------------------------------------------------------------------
switch (expression) {
case value1:
// value1에 대한 코드
break;
case value2:
// value2에 대한 코드
break;
default:
// 어떤 경우에도 일치하지 않을 때 실행될 코드
}
//-------------------------------------------------------------------
(condition) ? expression1 : expression2;
반복문
for, while, do-while은 자바, for-in문은 코틀린을 닮음
for (var i = 0; i < 5; i++) {
// 반복 실행되는 코드
}
//-------------------------------------------------------------------
while (condition) {
// 조건이 참인 동안 반복 실행되는 코드
}
//-------------------------------------------------------------------
do {
// 조건이 참인 동안 반복 실행되는 코드
} while (condition);
//-------------------------------------------------------------------
var numbers = [1, 2, 3, 4, 5];
for (var number in numbers) {
// numbers의 각 요소에 대해 반복 실행되는 코드
}
함수
선언부
반환타입 함수이름(매개변수) {
// 함수 몸체
}
위에서 말했듯이 리턴이 명시적이라 타입 추론이 가능하다면 반환타입을 생략가능
선택적 매개변수
Dart에서는 선택적 매개변수를 사용하여 함수 호출 시 일부 매개변수를 생략할 수 있습니다. 선택적 매개변수는 []로 감싼 것으로 표시되며, 기본값을 지정할 수도 있습니다.
void printUserInfo(String name, [int age = 0, String city = 'Unknown']) {
print('Name: $name');
print('Age: $age');
print('City: $city');
}
void main() {
printUserInfo('Alice');
}
이름 지정 매개변수
이름 지정 매개변수는 함수 호출 시 매개변수의 이름을 명시적으로 지정하여 인수를 전달하는 방식입니다. 함수 선언 시 중괄호 {}로 감싼 매개변수들을 선언하고, 함수 호출 시에는 매개변수의 이름과 함께 인수를 전달합니다. 이름 지정 매개변수를 사용하면 인수의 순서에 구애받지 않고 명시적으로 값을 전달할 수 있습니다.
void printUserInfo(String name,{int age = 3 , String? city}) {
print('Name: $name');
print('Age: $age');
print('City: $city');
}
void main() {
printUserInfo('John', age: 30, city: 'New York');
}
이름지정 매개변수 또한 선택적 매개변수처럼 생략이 가능하기 때문에 생략할 경우를 대비해 그 값이 Nullable 하거나 default 값을 가지고 있어야 합니다. 그렇지만 함수 자체에서 그값이 필수적으로 필요할때는 매개변수 선언부 자료형 앞에 required를 추가하여 값을 필수적으로 넣어줄 것을 강제할 수 있습니다.
익명함수
익명 함수는 이름이 없는 함수로, 다른 함수에 전달하거나 변수에 할당하여 사용할 수 있습니다. 익명 함수는 () { } 형태로 작성됩니다.
void executeFunction(Function function) {
function();
}
void main() {
executeFunction(() {
print('This is an anonymous function.');
});
}
화살표 함수
화살표 함수는 단일 표현식을 가진 함수를 간략하게 작성하는 방법입니다. => 기호를 사용하여 함수의 매개변수와 표현식을 연결합니다. 반환값은 자동으로 표현식의 결과로 처리됩니다.
int multiply(int a, int b) => a * b;
void main() {
print(multiply(5, 3)); // 15
}
클래스
Dart에서 클래스는 객체 지향 프로그래밍의 핵심 요소입니다. 클래스는 객체의 구조와 행위를 정의하는 데 사용되며, 객체를 생성하기 위한 템플릿 역할을 합니다. 클래스를 사용하여 객체를 생성하고 관리할 수 있습니다.
선언부
class ClassName extends ParentClass { //extends ParentClass 부분은 상속할경우 추가
// 멤버 변수 (속성)
dataType variableName;
// 생성자
ClassName(constructorArguments) {
// 생성자 로직
}
// 멤버 메서드 (행위)
// @override -> 상속함수 재정의시 anotation 사용
returnType methodName(methodArguments) {
// 메서드 로직
}
// 기타 멤버 (게터, 세터 등)
//부모의 함수는 super로 호출
}
인터페이스
//선언부
class InterfaceName {
// 인터페이스의 메서드 및 속성 정의
}
class ClassName implements InterfaceName {
// 인터페이스에서 정의한 모든 메서드 및 속성 구현
}
//예시
class Printable {
void printInfo();
}
class Person implements Printable {
String name;
Person(this.name);
@override
void printInfo() {
print('Person: $name');
}
}
void main() {
Person person = Person('Alice');
person.printInfo(); // 출력: Person: Alice
}
Dart에서 인터페이스는 암시적으로 정의되며, 클래스가 특정 인터페이스를 구현하기 위해서는 해당 인터페이스의 모든 멤버를 구현해야 합니다. 인터페이스는 클래스와 분리된 개체로 존재하지 않으며, 단지 클래스가 구현해야 하는 메서드 및 속성의 시그니처를 제공합니다.
- 마치며 -
이번에 Dart를 공부하면서 언어 자체에 큰 어려움은 없었다고 느꼈습니다. 1급 객체와 익명 함수의 지원만으로도 많은 작업을 수행할 수 있어서 놀라웠습니다. 또한, Dart에서는 long, short, float, char와 같은 자료형이 없다는 점이 흥미로웠습니다. 이전에는 작은 테스트 케이스에는 short나 byte를 자주 사용했는데, int가 모든 정수를 포함한다는 사실도 신기했지만, 메모리 관리에는 우려가 있었습니다. 이에 대해 조사해보았지만, 현대의 컴퓨팅 환경에서는 정수의 크기에 따른 메모리 사용이 큰 문제가 되지 않는다는 것을 알게 되었습니다. 이것이 최근 언어들의 특징이라고 생각하니 흥미로웠습니다.
참고 :
'Flutter > Dart' 카테고리의 다른 글
[Dart] 비동기 작업 클래스, Future (0) | 2023.06.12 |
---|---|
[Dart] Cascade Operator 와 Spread Operator (0) | 2023.06.10 |
[Dart] Collection과 Iterable 데이터들을 다루기 (0) | 2023.06.09 |