민프
[Flutter] Dart언어에서 알면 좋은 점 (Feat. 객체지향언어) 본문
Main 함수
Dart에서 Main함수는 모든 Dart 프로그램의 Entry point이기 때문에 중요하다
만약 main을 다른 함수명으로 바꾼다면 아래 사진과 같이 Run | Debug 내용이 없어지게 되고, 실제로 이 코드를 강제로 실행하려고 하면
'main'이 없어서 에러가 나게 된다.
세미클론
세미클론을 끝에 꼭 붙여줘야한다.
변수 - 선언
변수를 선언하는 방식에는 2가지가 있는데
결론적으로 Dart 스타일가이드에서는 메소드 안에서 지역변수를 선언하는 상황이라면 var을 사용하고,
class에서 변수나 property를 선언할 때에는 타입을 지정해주는 것을 권장하고 있다.
1. Var 변수
TypeScript와 같은 것 같은데 아래 코드와 같이 변수의 타입을 꼭 구체화 할 필요는 없다.
void main(){
var id = "민프";
}
왜냐하면 Dart 컴파일러는 id가 String(문자열)이라는 것을 알고 있기 때문이다.
아래 사진을 보면 'id' 에 마우스 커서를 대면 현재 인식 된 타입을 보여주는데 String이라고 인식하고 있는 것을 확인할 수 있다.
하지만 그 이후에 다른 타입의 값을 넣으면 에러가 날 수 있다
2. 명시적 선언
아래 사진과 같이 명시적으로 앞에 변수를 넣어서 선언을 해줄 수 있는데, 똑같이 String으로 잘 인식 된 것을 확인할 수 있다.
2-1. Dynamic 타입
TypeScript에서 any타입과 같은건데 결론적으로 여러가지 타입을 가실 수 있는 변수에 쓰는 키워드이다.
아래 사진과 같이 선언 할 때 변수에 아무것도 지정해주지 않으면 dynamic으로 선언이 되게 되는데
사진에서와 같이 dynamic으로 선언 된 id에다가 String값과 number값을 넣어줬는데 에러가 나지 않는 것을 확인할 수 있다.
아래 코드와 같이 var로 선언하지 않고 dynamic으로 선언하고 사용해도 된다.
void main(){
dynamic id;
id ="민프";
id =123;
}
만약 하나의 변수에 여러가지 타입이 사용되는데 그에 따른 분기 처리를 하고싶다면
아래 코드와 같이 if문을 사용해서 분기 처리를 해주면 된다. (하지만. .이렇게 작업하는건 추천하지 않는다.)
void main(){
dynamic id;
if(id is String){
id.toString();
}
if(id is int){
id.compareTo(other);
}
}
변수 - Null Safety
https://dart-ko.dev/null-safety/understanding-null-safety
null Safety란 어떤 변수, 데이터가 null이 될 수 있음을 명시하는 걸 말하는데
실 서비스를 하는 입장에서는 필수적으로 대응을 해야하는 부분이다.
기본적으로 변수를 선언하면 거의 모든 변수는 Non-nullable인데 여기에서 변수 앞에 '?'를 붙이면 null이 될 수 있다는 것을 알려주는 의미를 부여한다.
void main(){
String? id = '민프';
id = null;
if(id != null){
// Null 이 아닐 때 실행
}
}
이것을 아래 코드와 같이 사용할 수 있다.
void main(){
String? id = '민프';
id = null;
id?.isNotEmpty; // null이 아니라면 isNotEmpty 속성을 요청
}
변수 - Const
javascript, Typescript의 const는 Dart의 final과 비슷한데
Dart의 const는 JavaScript, Typescript와 다르다.
dart에서의 const는 compile-time constant를 만들어준다.
https://dart-tutorial.com/useful-information/final-vs-const-in-dart/
위 링크를 참고해서 compile-time constant가 뭔지 말해보자면
결론적으로 단순히 final이 변수가 다시 할당되지 않음을 의미하고,
const는 컴파일타임에 상수 값을 평가하여 변수에 할당하는 것을 의미하는데,
프로그램이 실행되기 전에 다음 개체가 인스턴스화될 수 있고 인스턴스화될 것임을 의미한다.
정리하자면 프로그램이 실행되기 전 고정값을 지정해주는 건 const,
프로그램이 실행되고 나서 값을 고정 시켜주는건 final이라는 것이다.
쉽게 말하자면
프로그램이 실행되고 나서 키보드로 id값을 입력해서 그 id값을 변경되지 않도록 선언하는 건 final
프로그램이 실행되기 전 id값을 하드코딩을 해서 변경되지 않도록 선언하는건 const 이라는 것이다.
const와 final변수에 대해서는 아래 링크에서 알아보았으니 참고해주세요
DataTypes - Set 과 List의 차이점
set에 속한 모든 아이템들은 유니크하고
List에 속한 아이템들은 유니크 하지 않는다.
함수 - Named Parameters, Name Argument
TypeScript에도 있는 부분인데 함수에다가 파라미터를 지정할 때 순서를 기억하는게 아니라 파라미터 변수 명을 입력하게 해서 직관적으로 볼 수 있게 하고, 필요한 필수 파리미터 값과 옵션 값을 나눌 수 있다.
// Name Argument + Name Parameters => defalut 값 지정
String userInfo2({String name ="defalut", int age= 0}){
return "userName : $name, userAge: $age";
}
// Name Argument + Name Parameters => required 필수 값 지정
String userInfo3({required String name, required int age}){
return "userName : $name, userAge: $age";
}
// 옵션 값 지정
String userInfo4(String name, int age, [String? contry ="Seoul"]){
return "userName : $name, userAge: $age";
}
void main(){
print(userInfo2(name: "민프", age: 10));
}
클래스(Classes) - 생성자(Constructor)
여러 객체지향언어에서 사용되는 클래스와 생성자를 사용해서 로직을 설계하는데 코드는 아래와 같다.
class User{
late String name; // 초기값을 설정해주던지 아니면 defalut값을 설정해놓던지
late int age; // 초기값을 설정해주던지 아니면 defalut값을 설정해놓던지
User(String name, int age){
this.name = name;
this.age = age;
}
void welcomeUser(){
print("Hello $name Welcome To Our Service" );
}
}
class Master{
String name;
int age;
Master(this.name, this.age); //이런식으로 하면 late를 사용하지 않아도 된다.
void welcomeMaster(){
print("Hello $name Welcome To Our Service" );
}
}
void main(){
var user1 = User("민프",10);
user1.welcomeUser();
}
나는 주로 Master에서 선언 된 생성자 코드를 사용한다.
클래스(Classes) - 생성자(Constructor) - Named Counstructor Parameters
생성자에서도 순서를 기억 할 필요없이 파라미터를 이름으로 넣어줄 수 있다.
class Chif{
String name;
int age;
Chif({required this.name,required this.age}); // 기본값을 주던지, required를 붙이던지
void welcomeMaster(){
print("Hello $name Welcome To Our Service" );
}
}
void main(){
var chif1 = Chif(name: "민프치프",age: 20);
}
클래스(Classes) - 생성자(Constructor) - Named Counstructor
기본적으로 호출되는 생성자가 있고, 조금은 다르게 동작하는 또 다른 생성자를 가지고 싶으면 어떻게 할까?
아래 코드를 보면 Player에서 생성자 기본 호출을 하는 부분이 있고, 다르게 동작하는 또 다른 생성자가 있다.
이렇게도 생성자를 사용할 수 있다.
class Player{
String name,grade;
int age;
Player(this.name, this.age, this.grade); // 생성자 기본 호출
// 다르게 동작하는 또 다른 생성자
Player.createGoodPlayer({
required String name,
required int age,
}) : this.name=name,
this.age = age,
this.grade="Good Player";
void welcomePlayer(){
print("Hello $name Welcome To Our Service" );
}
}
void main(){
var user1 = User("민프",10);
user1.welcomeUser();
var chif1 = Chif(name: "민프치프",age: 20);
var goodPlayer = Player.createGoodPlayer(name:"민프", age: 10);
}
클래스(Classes) - Cascade Notation
클래스에 대한 객체의 값을 수정할 때 방법이 2가지가 있는데 아래 코드와 같다.
var chif1 = Chif(name: "민프치프",age: 20);
chif1.name="오프치프";
chif1.age=20;
// Cascade Notation
var chif2 = Chif(name: "민프치프",age: 20) //Cascade Notation는 세미클론을 마지막에 붙임
..age=20
..name="민프";
chif1에서와 같이 변경할 수도 있고,
chif2에서와 같이 Cascade Notation을 사용해서 변경할 수 있다.
클래스(Classes) - enum Class
Enum은 실제 개발에서도 많이 사용되는데 오타확률을 적게 해주고, 유지보수에도 도움을 준다.
https://ko.wikipedia.org/wiki/%EC%97%B4%EA%B1%B0%ED%98%95
Enum은 단순히 열거형이라고 부른다.
즉, 서로 연관된 상수들의 집합을 의미한다.
Dart뿐만 아니라 다른 언어에서도 많이 사용 되는 enum class이다.
예들 들어서)
자동차 타입 : SUV, CUV, Sedan이 있다고 해보자
클래스를 만들거나 해당 타입을 사용할 때 마다 직접 타이핑을 해서 넣게 되면 아래와 같이 오타가 날 가능성이 생기게 되는데
Car(type:"SUV")
Car(type:"CIV")
Car(type:"Saden")
아래와 같이 enum을 지정하면 자동완성 기능도 제공되고 오타가 날 가능성이 현저하게 줄여질 수 있다.
enum CarType{SUV, CUV, Sedan}
Car(type:CarType.SUV)
Car(type:CarType.CUV)
Car(type:CarType.Sedan)
클래스(Classes) - 추상 클래스(Abstract Classes)
추상화 클래스는 자바, 코틀린에서 사용해봤는데
클래스와 추상 클래스의 가장 큰 차이점은
추상 클래스는 반드시 오버라이딩, 상속 해야만 사용할 수 있다는 점이다.
즉, 클래스는 중복이 되는 부분, 공통적인 부분을 만든 것이라고 생각하면
추상 클래스는 기존 클래스에서 뭔가 더 필요한 부분을 재정의하여 사용하는 클래스라고 생각하면 된다.
아래 코드를 참고하자
abstract class Human{
void walk();
}
class User extends Human{
late String name; // 초기값을 설정해주던지 아니면 defalut값을 설정해놓던지
late int age; // 초기값을 설정해주던지 아니면 defalut값을 설정해놓던지
User(String name, int age){
this.name = name;
this.age = age;
}
void walk(){
print("This is abstract class");
}
void welcomeUser(){
print("Hello $name Welcome To Our Service" );
}
}
클래스(Classes) - 상속 (Inheritance)
상속은 객체지향언어라면 자주 사용하게 되는데
부모클래스에서 자식 클래스의 변수 및 메서드를 사용할 수 있고, 재정의를 할 수 있도록 해주는 것을 의미한다.
사용 방법은 자식 클래스에서 extends를 넣어서 사용해준다.
아래 코드를 참고하자
class Human {
final String name;
Human({required this.name});
void sayHello(){
print("hello $name");
}
}
enum Team {blue,red}
class Player extends Human{
final Team team;
//Human이라는 부모 클래스를 상속 받았으니 super를 사용해서 Human안에 있는 파라미터도 넣어줘야해
// super는 부모 클래스와 상호작용 할 수 있게 해준다.
// 즉 super에 name을 전달해주면 이 클래스에 전달 된 name과 함께 호출하게 되는거다
Player({required this.team, required String name}):super(name: name);
// 부모에서 선언 된 sayHello 메서드를 override로 커스텀 할 수 있다.
@override
void sayHello(){
super.sayHello(); // super를 통해서 부모에서 선언 된 부분들을 가지고 올 수 있다.
print("override SayHello ${team}");
}
}
void main (){
var player1 = Player(team: Team.red,name: "민프");
player1.sayHello();
}
클래스(Classes) - 믹스인 (Mixin or Mix-in)
https://ko.wikipedia.org/wiki/%EB%AF%B9%EC%8A%A4%EC%9D%B8
Mixin은 객체지향언어라면 사용하게 되는 건데
Mixin은 생성자가 없는 클래스를 의미한다.
그래서 보통 클래스에 프로퍼티들을 추가할 때 사용하게 된다.
사용 방법은 이번에는 extends를 사용하는게 아니라 with를 사용한다.
아래 코드를 참고하자
// Mixin 클래스 선언
mixin Strong {
final double strenghtLevel = 1500.99;
}
// Mixin 클래스 선언
mixin QuickRunner {
void runQuick(){
print("rumn");
}
}
class Player with Strong, QuickRunner{
final Team team;
Player({required this.team});
}
void main (){
var player1 = Player(team: Team.red);
}
위 와 같이 Mixin클래스를 선언하면 사용하는 클래스에게 다중상속을 하기 쉬워진다.
지금은 Player클래스만 있지만 여러 클래스들이 있게 된다면 유지보수에 용이해질 것 이다.
참고링크
https://dart.dev/effective-dart/style
https://dart-ko.dev/language/variables
https://dart-tutorial.com/useful-information/final-vs-const-in-dart/
https://www.reddit.com/r/dartlang/comments/mo7239/compiletime_vs_runtime_constants/
https://ko.wikipedia.org/wiki/%EB%AF%B9%EC%8A%A4%EC%9D%B8
'[Flutter]' 카테고리의 다른 글
[Flutter] MainAxisAlignment, CrossAxisAlignment 정렬하기 (기록) (0) | 2023.08.08 |
---|---|
[Flutter] React-Native 말고 Flutter를 선택한 이유 (0) | 2023.08.08 |
[Flutter] 플러터 다트(Dart)언어란? 구글이 Flutter에 Dart언어를 선택한 이유? (feat. DartPad) (0) | 2023.08.07 |
[Flutter] M1 MAC에서 android Studio Flutter 개발환경 구축하기 (feat. Error installing cocoapods) (0) | 2023.08.04 |
[Flutter] http 통신 GET,POST해보기 (2) | 2023.01.09 |