AIoT

AIoT 정규 52일차

맥기짱짱 2024. 3. 25. 17:17

Dart

Dart에서는 다양한 유형의 매개변수를 사용할 수 있습니다: 위치 매개변수(Positional Parameters)와 이름 매개변수(Named Parameters)입니다.

  • 위치 매개변수(Positional Parameters): 함수를 호출할 때 매개변수의 순서에 따라 값을 전달해야 합니다. 예를 들어, 아래의 함수 greet에서 name과 title은 위치 매개변수입니다.
String greet(String name, String title) {
  return 'Hello $title$name!';
}
void main() {
  print(greet('Alice', 'Professor')); // Output: Hello Professor Alice!
}

위치 매개변수는 함수를 호출할 때 매개변수의 순서를 따라야 하므로, 매개변수의 순서를 바꾸면 함수가 제대로 작동하지 않습니다.

  • 이름 매개변수(Named Parameters): 중괄호 {}로 둘러싸인 매개변수입니다. 이름 매개변수를 사용하면 함수를 호출할 때 매개변수의 이름을 명시적으로 지정하여 값을 전달할 수 있습니다. 이렇게 하면 함수 호출이 더 명확해지며, 매개변수의 순서를 바꿔도 문제가 발생하지 않습니다.
String greet(String name, {String title = ''}) {
  if (title.isEmpty) {
    return 'Hello $name!';
  }
  return 'Hello $title$name!';
}
void main() {
  print(greet('Alice', title: 'Professor')); // Output: Hello Professor Alice!
}

이름 매개변수는 선택적이며 기본값을 가질 수 있습니다. 함수를 정의할 때 이름 매개변수에 기본값을 지정해야 합니다.
참고로 Dart에서는 선택적 위치 매개변수와 이름 매개변수를 동시에 사용할 수 없습니다.

 

  • Null Aware Argument: Dart에서는 null 값을 처리하기 위해 다양한 Null Aware 연산자를 제공합니다. 이 연산자들은 값이 null인 경우를 처리하는데 도움이 됩니다. Null Aware 연산자에는 다음과 같은 것들이 있습니다:
연산자 내용
?? If-null 연산자입니다. 값이 null이 아니면 값을 반환하고, 그렇지 않으면 value_if_null을 반환합니다.
??= Null-aware 할당 연산자입니다. 값이 null인 경우에만 값을 할당합니다.
?. Null-aware 접근 연산자입니다. 객체가 null인 경우 null을 반환합니다.
! Null 단언 연산자입니다. 값이 null이 아님을 단언합니다.
  • Optional Positional Argument: Dart에서는 선택적 위치 매개변수를 지원합니다. 이 매개변수들은 함수 호출 시 일부 매개변수를 선택적으로 제공할 수 있게 해줍니다. 선택적 위치 매개변수는 대괄호 []로 묶어 표시하며, 기본값을 가질 수 있습니다. 예를 들어, 아래의 함수 getHttpUrl에서 port는 선택적 위치 매개변수입니다.
getHttpUrl(String server, String path, [int port=80]) {
  // ...
}

위의 함수는 port 매개변수를 제공하거나 생략하고 호출할 수 있습니다. 선택적 위치 매개변수는 여러 개를 지정할 수 있지만, 순서대로 제공해야 합니다. 즉, port를 생략하고 numRetries를 제공하려면 이름 매개변수를 사용해야 합니다.

getHttpUrl(String server, String path, [int port=80, int numRetries=3]) {
  // ...
}

 

이렇게 하면 함수 호출이 더 명확해지며, 매개변수의 순서를 바꿔도 문제가 발생하지 않습니다.

 

  • Typedef:
    • Typedef는 함수에 대한 사용자 정의 식별자(별칭)를 생성하는 데 사용됩니다. 이를 통해 프로그램 코드에서 함수 대신 해당 식별자를 사용할 수 있습니다. Typedef를 사용하면 함수의 매개변수를 정의할 수 있습니다.
    • Typedef는 종종 타입 별칭이라고도 불리며, 이는 타입에 대한 참조를 간결하게 만드는 데 도움이 됩니다. 다음은 IntList라는 타입 별칭을 선언하고 사용하는 예입니다.
typedef IntList = List<int>;
IntList il = [1, 2, 3];

 

 

>>>타입 별칭은 타입 매개변수를 가질 수 있습니다. 예를 들어, 아래의 ListMapper는 타입 매개변수 X를 가지고 있습니다.

typedef ListMapper<X> = Map<X, List<X>>;
Map<String, List<String>> m1 = {}; // Verbose.
ListMapper<String> m2 = {}; // Same thing but shorter and clearer.

 

>>>대부분의 상황에서 함수에 대해서는 Typedef 대신 인라인 함수 타입을 사용하는 것이 권장됩니다. 

typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
  assert(sort is Compare<int>); // True!
}

:이렇게 하면 함수 타입이 변수에 할당될 때 타입 정보를 유지할 수 있습니다.

 

 

  • Named Constructor
    • 클래스에 여러 생성자를 구현하거나 추가적인 명확성을 제공하기 위해 사용됩니다.
    • Named Constructor는 클래스 이름과 동일한 이름의 함수를 생성하여 선언합니다.
    • 선택적으로 Named Constructor를 설명하는 추가 식별자를 사용할 수 있습니다. 

다음은 Point 클래스에 대한 Named Constructor인 Point.origin()의 예입니다.>>

const double xOrigin = 0;
const double yOrigin = 0;

class Point {
  final double x;
  final double y;

  // Sets the x and y instance variables
  // before the constructor body runs.
  Point(this.x, this.y);

  // Named constructor
  Point.origin()
      : x = xOrigin,
        y = yOrigin;
}

위의 코드에서 Point.origin()은 Named Constructor로, x와 y를 원점의 좌표로 초기화합니다. 이렇게 하면 Point 클래스의 인스턴스를 생성할 때 원점을 나타내는 특별한 경우를 명확하게 표현할 수 있습니다.

그리고 Dart에서는 생성자의 매개변수를 인스턴스 변수에 할당하는 일반적인 패턴을 간단하게 만들기 위해 syntactic sugar를 제공합니다. 이를 initializing formal parameters라고 합니다. 이는 생성자 선언에서 this.propertyName을 직접 사용하고, 본문을 생략함으로써 가능합니다. 다음은 Point 클래스의 생성자에서 initializing formal parameters를 사용하는 예입니다.

class Point {
  final double x;
  final double y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}

위의 코드에서 Point(this.x, this.y)는 x와 y를 초기화하는 syntactic sugar입니다. 이렇게 하면 생성자 본문을 작성하지 않고도 인스턴스 변수를 초기화할 수 있습니다.

 
  • Enum
    • 주로 명명된 상수 값을 정의하는 데 사용되는 특별한 종류의 클래스.
    • 고유한 상수 값을 가지는 씸볼릭 이름(멤버)의 집합.
    • enum 키워드를 사용하여 선언됩니다.
    • Enum의 각 값은 고유한 인덱스를 가지며, 이 인덱스는 값이 Enum 선언에서 위치한 순서를 나타냅니다.


다음은 간단한 Enum의 예입니다.

enum Color {
  red,
  green,
  blue
}

위의 코드에서 Color는 Enum이며, red, green, blue는 Enum의 멤버입니다. 이렇게 선언된 Enum의 멤버는 프로그램 코드에서 상수처럼 사용할 수 있습니다.

또한 Dart 2.17 버전부터는 발전된 Enum(Enhanced Enums)을 지원합니다. 발전된 Enum은 필드, 메서드, 상수 생성자를 가진 클래스를 선언하는 데 사용됩니다.

 

다음은 발전된 Enum의 예입니다.

enum Vehicle implements Comparable<Vehicle> {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires;
  final int passengers;
  final int carbonPerKilometer;

  int get carbonFootprint => (carbonPerKilometer / passengers).round();
  bool get isTwoWheeled => this == Vehicle.bicycle;

  @override
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}

: 위의 코드에서 Vehicle은 발전된 Enum이며, car, bus, bicycle은 Enum의 멤버입니다. 각 멤버는 필드(tires, passengers, carbonPerKilometer), 메서드(carbonFootprint, isTwoWheeled, compareTo)를 가집니다. 이렇게 선언된 발전된 Enum의 멤버는 프로그램 코드에서 클래스의 인스턴스처럼 사용할 수 있습니다.

* tip: Enum의 멤버 가져오기

 : Dart에서 enum의 멤버는 고유한 상수 값을 가지는 씸볼릭 이름입니다. 이러한 씸볼릭 이름을 문자열로 가져오려면, Dart 2.15 버전부터 제공하는 name 속성을 사용할 수 있습니다. name 속성은 enum 값의 식별자를 문자열로 반환합니다.

 

enum Team { red, blue }

enum XPLevel { beginner, medium, pro }

class Player {
  String name;
  XPLevel xp;
  Team team;

  Player({
    required this.name,
    required this.xp,
    required this.team,
  });

  void sayHello() {
    print("Hello! my name is $name, and my xp is ${xp.name} my team is ${team.name}");
  }
}

void main() {
  var sarang = Player(name: 'Sarang', xp: XPLevel.pro, team: Team.red);
  var mcgi = Player(name: "McGi", xp: XPLevel.beginner, team: Team.blue);
  sarang.sayHello();
  mcgi.sayHello();
}


예를 들어, Team.red의 name 속성을 호출하면 문자열 red를 반환합니다. 따라서 ${team.name}은 Team.red의 경우 red를, Team.blue의 경우 blue를 출력합니다.

마찬가지로, ${xp.name}은 XPLevel.beginner의 경우 beginner, XPLevel.medium의 경우 medium, XPLevel.pro의 경우 pro를 출력합니다.

따라서 코드에서 ${xp.name}과 ${team.name}을 사용하면 각각 XPLevel과 Team enum의 멤버 이름을 문자열로 출력할 수 있습니다.

 

 

- Dart에서는 추상 클래스(Abstract Classes), 상속(Inheritance), 그리고 믹스인(Mixins)이라는 개념을 사용하여 코드의 재사용성을 높이고, 클래스 간의 관계를 구성합니다.

  • 추상 클래스(Abstract Classes): 추상 클래스는 하나 이상의 추상 메서드(구현이 없는 메서드)를 포함하는 클래스를 말합니다. 추상 클래스는 abstract 키워드를 사용하여 선언하며, 추상 클래스의 인스턴스는 생성할 수 없습니다. 추상 클래스는 주로 다른 클래스가 상속받아 사용하도록 설계됩니다.
abstract class AbstractClass {
  void abstractMethod();
}

위의 코드에서 AbstractClass는 추상 클래스이며, abstractMethod는 추상 메서드입니다.

  • 상속(Inheritance): 상속은 한 클래스가 다른 클래스의 속성과 메서드를 물려받는 메커니즘입니다. Dart는 단일 상속만 지원하며, extends 키워드를 사용하여 상속을 구현합니다.
class ParentClass {
  void parentMethod() {
    print('This is a method from ParentClass.');
  }
}

class ChildClass extends ParentClass {
  void childMethod() {
    print('This is a method from ChildClass.');
  }
}

위의 코드에서 ChildClass는 ParentClass를 상속받아 parentMethod를 사용할 수 있습니다.

  • 믹스인(Mixins): 믹스인은 여러 클래스 계층에서 코드를 재사용하는 방법을 제공합니다. 믹스인은 mixin 키워드를 사용하여 선언하며, with 키워드를 사용하여 믹스인을 적용합니다.
mixin Mixin {
  void mixinMethod() {
    print('This is a method from Mixin.');
  }
}

class MyClass with Mixin {
  void myMethod() {
    print('This is a method from MyClass.');
  }
}

위의 코드에서 MyClass는 Mixin 믹스인을 사용하여 mixinMethod를 사용할 수 있습니다.

 

'AIoT' 카테고리의 다른 글

AIoT 정규 54일차  (0) 2024.03.27
AIoT 정규 53일차  (0) 2024.03.26
AIoT 정규 51일차  (0) 2024.03.21
AIoT 정규 50일차  (3) 2024.03.14
AIoT 정규 49일차  (0) 2024.03.13