Dart Language Tour #6

t0dd·2020년 9월 25일
0

Dart Language Tour

목록 보기
6/6
post-thumbnail

클래스

Dart는 클래스와 믹스 인 기반 상속이있는 객체 지향 언어입니다. 모든 객체는 클래스의 인스턴스이며 모든 클래스는 Object의 자손입니다. Mixin 기반 상속은 모든 클래스 (Object 제외)에 정확히 하나의 수퍼 클래스가 있지만 클래스 본문은 여러 클래스 계층에서 재사용 될 수 있음을 의미합니다. 확장 메서드는 클래스를 변경하거나 하위 클래스를 만들지 않고 클래스에 기능을 추가하는 방법입니다.

클래스 멤버 사용

개체에는 함수와 데이터 (각각 메서드 및 인스턴스 변수)로 구성된 멤버가 있습니다. 메소드를 호출하면 객체에서 호출합니다. 메소드는 해당 객체의 함수와 데이터에 액세스 할 수 있습니다.

인스턴스 변수 또는 메서드를 참조하려면 점(.)을 사용합니다.

var p = Point(2, 2);

// Set the value of the instance variable y.
p.y = 3;

// Get the value of y.
assert(p.y == 3);

// Invoke distanceTo() on p.
double distance = p.distanceTo(Point(4, 4));

왼쪽 피연산자가 null 일 때 예외를 방지하려면 . 대신에 ?. 를 사용하세요.

p?.y = 4;

생성자 사용

생성자를 사용하여 개체를 만들 수 있습니다. 생성자 이름은 ClassName 또는 ClassName.identifier 일 수 있습니다. 예를 들어 다음 코드는 Point()Point.fromJson() 생성자를 사용하여 Point 객체를 만듭니다.

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

아래 코드는 동일한 효과가 있지만 생성자 이름 앞에 선택적 new 키워드를 사용합니다.

var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});

new 키워드는 Dart2 에서 선택 사항이 되었습니다.

일부 클래스는 상수 생성자를 제공합니다. 상수 생성자를 사용하여 컴파일 타임 상수를 만들려면 생성자 이름 앞에 const 키워드를 넣으십시오.

var p = const ImmutablePoint(2, 2);

두 개의 동일한 컴파일 타임 상수를 생성하면 단일 표준 인스턴스가 생성됩니다.

var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // 두 객체는 같습니다.

상수 컨텍스트 내에서 생성자 또는 리터럴 앞에 const를 생략 할 수 있습니다. 예를 들어, Map 상수를 만드는 다음 코드를 살펴보십시오.

// const 키워드를 아주 많이 사용합니다.
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

const 키워드의 첫 번째 사용을 제외하고 모두 생략 할 수 있습니다.

// const 키워드를 단 한번만 사용하여도 위 코드와 같습니다.
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

상수 생성자가 상수 컨텍스트 외부에 있고 const없이 호출되면 상수가 아닌 객체를 만듭니다.

var a = const ImmutablePoint(1, 1); // 상수 생성
var b = ImmutablePoint(1, 1); // 비 상수 생성

assert(!identical(a, b)); // 같지 않습니다.

const 키워드는 Dart2의 상수 컨텍스트 내에서 선택 사항이되었습니다.

객체 유형 가져오기

런타임에 객체의 유형을 가져 오려면 Type 객체를 반환하는 ObjectruntimeType 속성을 사용할 수 있습니다.

print('The type of a is ${a.runtimeType}');

여기까지 클래스 사용 방법을 살펴 보았습니다. 이 섹션의 나머지 부분에서는 클래스를 구현하는 방법을 보여줍니다.

인스턴스 변수

인스턴스 변수를 선언하는 방법은 다음과 같습니다.

class Point {
  double x; // Declare instance variable x, initially null.
  double y; // Declare y, initially null.
  double z = 0; // Declare z, initially 0.
}

초기화되지 않은 모든 인스턴스 변수의 값은 null입니다.

모든 인스턴스 변수는 암시 적 getter 메서드를 생성합니다. 최종 인스턴스 변수가 아닌 경우에도 암시 적 setter 메서드가 생성됩니다. 자세한 내용은 Getters 및 Setters를 참조하십시오.

class Point {
  double x;
  double y;
}

void main() {
  var point = Point();
  point.x = 4; // Use the setter method for x.
  assert(point.x == 4); // Use the getter method for x.
  assert(point.y == null); // Values default to null.
}

(생성자나 메서드 대신) 선언 된 인스턴스 변수를 초기화하면 인스턴스가 생성될 때 값이 설정되며, 생성자 및 초기화 목록이 실행되기 전입니다.

생성자

클래스와 이름이 같은 함수를 생성하여 생성자를 선언합니다 (명시 된 생성자에 설명 된 추가 식별자도 추가 할 수 있음). 생성자의 가장 일반적인 형태인 일반 생성자는 클래스의 새 인스턴스를 만듭니다.

class Point {
  double x, y;

  Point(double x, double y) {
    // There's a better way to do this, stay tuned.
    this.x = x;
    this.y = y;
  }
}

this 키워드는 현재 인스턴스를 참조합니다.

this는 이름 충돌이있는 경우에만 사용하십시오. 그렇지 않으면 Dart 스타일은 this를 생략합니다.

생성자 인수를 인스턴스 변수에 할당하는 패턴은 매우 일반적이므로 Dart에는 이를 쉽게 하기위한 문법적 설탕이 있습니다.

class Point {
  double x, y;

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

기본 생성자

생성자를 선언하지 않으면 기본 생성자가 제공됩니다. 기본 생성자에는 인수가 없으며 수퍼 클래스에서 인수가없는 생성자를 호출합니다.

상속되지 않는 생성자

하위 클래스는 수퍼 클래스에서 생성자를 상속하지 않습니다. 생성자를 선언하지 않는 하위 클래스에는 기본 (인수, 이름 없음) 생성자 만 있습니다.

명시된 생성자

명시된 생성자를 사용하여 클래스에 대해 여러 생성자를 구현하거나 추가 명확성을 제공합니다.

class Point {
  double x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

생성자는 상속되지 않습니다. 즉, 수퍼 클래스의 명시된 생성자가 하위 클래스에서 상속되지 않습니다. 슈퍼 클래스에 정의된 명시된 생성자로 서브 클래스를 생성하려면 해당 생성자를 서브 클래스에서 구현해야합니다.

기본이 아닌 슈퍼 클래스 생성자 호출

기본적으로 하위 클래스의 생성자는 수퍼 클래스의 명시되지 않은 인수없는 생성자를 호출합니다. 슈퍼 클래스의 생성자는 생성자 본문의 시작 부분에서 호출됩니다. 이니셜라이저 목록도 사용중인 경우 수퍼 클래스가 호출되기 전에 실행됩니다. 요약하면 실행 순서는 다음과 같습니다.

  1. 이니셜 라이저 목록
  2. 슈퍼 클래스의 인수없는 생성자
  3. 메인 클래스의 인수없는 생성자

수퍼 클래스에 이름이 지정되지 않은 인수없는 생성자가 없으면 수퍼 클래스의 생성자 중 하나를 수동으로 호출해야합니다. 생성자 본문 (있는 경우) 바로 앞에 콜론 (:) 뒤에 수퍼 클래스 생성자를 지정합니다.

다음 예제에서 Employee 클래스의 생성자는 수퍼 클래스 Person에 대해 명명 된 생성자를 호출합니다. 실행을 클릭하여 코드를 실행합니다.

코드
class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}
결과
in Person
in Employee

슈퍼 클래스 생성자에 대한 인수는 생성자를 호출하기 전에 평가되기 때문에 인수는 함수 호출과 같은 표현식이 될 수 있습니다.

class Employee extends Person {
  Employee() : super.fromJson(defaultData);
  // ···
}

슈퍼 클래스 생성자에 대한 인수는 this에 액세스 할 수 없습니다. 예를 들어, 인수는 인스턴스 메서드가 아닌 정적 메서드를 호출 할 수 있습니다.

이니셜라이저 목록

슈퍼 클래스 생성자를 호출하는 것 외에도 생성자 본문이 실행되기 전에 인스턴스 변수를 초기화 할 수도 있습니다. 이니셜라이저는 쉼표로 구분하십시오.

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, double> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

이니셜라이저의 오른쪽에는 this에 대한 액세스 권한이 없습니다.

개발 중에 이니셜 라이저 목록에서 assert를 사용하여 입력의 유효성을 검사 할 수 있습니다.

Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print('In Point.withAssert(): ($x, $y)');
}

이니셜라이저 목록은 최종 필드를 설정할 때 편리합니다. 다음 예제는 이니셜라이저 목록에서 세 개의 마지막 필드를 초기화합니다. 실행을 클릭하여 코드를 실행합니다.

코드
import 'dart:math';

class Point {
  final num x;
  final num y;
  final num distanceFromOrigin;

  Point(x, y)
      : x = x,
        y = y,
        distanceFromOrigin = sqrt(x * x + y * y);
}

main() {
  var p = new Point(2, 3);
  print(p.distanceFromOrigin);
}
결과
3.605551275463989

생성자 리디렉션

때때로 생성자의 유일한 목적은 동일한 클래스의 다른 생성자로 리디렉션하는 것입니다. 리디렉션 생성자의 본문이 비어 있으며 생성자 호출이 콜론 (:) 뒤에 표시됩니다.

class Point {
  double x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(double x) : this(x, 0);
}

상수 생성자

클래스가 변경되지 않는 객체를 생성하는 경우 이러한 객체를 컴파일 시간 상수로 만들 수 있습니다. 이렇게 하려면 상수 생성자를 정의하고 모든 인스턴스 변수가 최종 변수인지 확인해야 합니다.

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

상수 생성자가 항상 상수를 만드는 것은 아닙니다. 자세한 내용은 생성자 사용 섹션을 참조하세요.

팩토리 생성자

항상 클래스의 새 인스턴스를 만들지는 않는 생성자를 구현할 때 factory 키워드를 사용합니다. 예를 들어 팩토리 생성자는 캐시에서 인스턴스를 반환하거나 하위 유형의 인스턴스를 반환 할 수 있습니다. 팩토리 생성자의 또 다른 사용 사례는 이니셜라이저 목록에서 처리 할 수없는 로직을 사용하여 최종 변수를 초기화하는 것입니다.

다음 예제에서 Logger 팩토리 생성자는 캐시에서 객체를 반환하고 Logger.fromJson 팩토리 생성자는 JSON 객체에서 최종 변수를 초기화합니다.

class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(
        name, () => Logger._internal(name));
  }

  factory Logger.fromJson(Map<String, Object> json) {
    return Logger(json['name'].toString());
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

팩토리 생성자는 this에 액세스 할 수 없습니다.

다른 생성자와 마찬가지로 팩토리 생성자를 호출합니다.

var logger = Logger('UI');
logger.log('Button clicked');

var logMap = {'name': 'UI'};
var loggerJson = Logger.fromJson(logMap);

메서드

메서드는 개체에 동작을 제공하는 함수입니다.

인스턴스 메서드

객체의 인스턴스 메서드는 인스턴스 변수와 이에 액세스 할 수 있습니다. 다음 샘플의 distanceTo() 메서드는 인스턴스 메서드의 예시입니다.

import 'dart:math';

class Point {
  double x, y;

  Point(this.x, this.y);

  double distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

Getters 및 setters

GetterSetter는 개체 속성에 대한 읽기 및 쓰기 액세스를 제공하는 특수 메서드입니다. 각 인스턴스 변수에는 암시 적 getter와 적절한 경우 setter 가 있습니다. getset 키워드를 사용하여 gettersetter를 구현하여 추가 속성을 만들 수 있습니다.

class Rectangle {
  double left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  // Define two calculated properties: right and bottom.
  double get right => left + width;
  set right(double value) => left = value - width;
  double get bottom => top + height;
  set bottom(double value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

gettersetter를 사용하면 인스턴스 변수로 시작하고 나중에 클라이언트 코드를 변경하지 않고 메서드로 래핑 할 수 있습니다.

증가(++)와 같은 연산자는 getter가 명시 적으로 정의되었는지 여부에 관계없이 예상 된 방식으로 작동합니다. 예기치 못한 부작용을 방지하기 위해 연산자는 getter를 정확히 한 번 호출하여 해당 값을 임시 변수에 저장합니다.

추상 메서드

인스턴스, gettersetter 메서드는 추상적 일 수 있으며 인터페이스를 정의하지만 구현은 다른 클래스에 맡깁니다. 추상 메서드는 추상 클래스에만 존재할 수 있습니다.

메서드를 추상적으로 만들려면 메서드 본문 대신 세미콜론 (;)을 사용합니다.

abstract class Doer {
  // Define instance variables and methods...

  void doSomething(); // Define an abstract method.
}

class EffectiveDoer extends Doer {
  void doSomething() {
    // Provide an implementation, so the method is not abstract here...
  }
}

추상 클래스

abstract 한정자를 사용하여 인스턴스화가 불가능한 추상 클래스를 정의합니다. 추상 클래스는 종종 일부 구현과 함께 인터페이스를 정의하는 데 유용합니다. 추상 클래스가 인스턴스화 가능한 것처럼 보이게하려면 팩토리 생성자를 정의하십시오.

추상 클래스에는 종종 추상 메서드가 있습니다. 다음은 추상 메서드가있는 추상 클래스를 선언하는 예시입니다.

// This class is declared abstract and thus
// can't be instantiated.
abstract class AbstractContainer {
  // Define constructors, fields, methods...

  void updateChildren(); // Abstract method.
}

암묵적 인터페이스

모든 클래스는 클래스의 모든 인스턴스 멤버와 구현하는 인터페이스를 포함하는 인터페이스를 암시 적으로 정의합니다. B의 구현을 상속하지 않고 클래스 B의 API를 지원하는 클래스 A를 만들려면 클래스 A가 B 인터페이스를 구현해야합니다.

클래스는 하나 이상의 인터페이스를 구현절에서 선언 한 다음 인터페이스에 필요한 API를 제공하여 구현합니다. 예시를 들면,

// A person. The implicit interface contains greet().
class Person {
  // In the interface, but visible only in this library.
  final _name;

  // Not in the interface, since this is a constructor.
  Person(this._name);

  // In the interface.
  String greet(String who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.
class Impostor implements Person {
  get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

다음은 클래스가 여러 인터페이스를 구현하도록 지정하는 예시입니다.

class Point implements Comparable, Location {...}

클래스 확장

extends를 사용하여 하위 클래스를 만들고 super를 사용하여 수퍼 클래스를 참조합니다.

class Television {
  void turnOn() {
    _illuminateDisplay();
    _activateIrSensor();
  }
  // ···
}

class SmartTelevision extends Television {
  void turnOn() {
    super.turnOn();
    _bootNetworkInterface();
    _initializeMemory();
    _upgradeApps();
  }
  // ···
}

멤버 재정의

하위 클래스는 인스턴스 메서드, gettersetter를 재정의 할 수 있습니다. @override 주석을 사용하여 의도적으로 멤버를 재정의하고 있음을 나타낼 수 있습니다

class SmartTelevision extends Television {
  
  void turnOn() {...}
  // ···
}

형식이 안전한 코드에서 메서드 매개 변수 또는 인스턴스 변수의 형식을 좁히려면 covariant 키워드를 사용할 수 있습니다.

재정의 가능한 연산자

다음 표에 표시된 연산자를 재정의 할 수 있습니다. 예를 들어 Vector 클래스를 정의하는 경우 + 메서드를 정의하여 두 개의 벡터를 추가 할 수 있습니다.

!= 가 재정의 할 수있는 연산자가 아니라는 것을 알 수 있습니다. e1! = e2 표현식은! (e1 == e2)에 대한 문법적 설탕입니다.

다음은 +- 연산자를 재정의하는 클래스의 예시입니다.

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

  // Operator == and hashCode not shown. For details, see note below.
  // ···
}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}

==를 재정의하는 경우 Object의 hashCode getter도 재정의해야합니다. == 및 hashCode를 재정의하는 예시는 맵 키 구현을 참조하세요.

일반적으로 재정의에 대한 자세한 내용은 클래스 확장을 참조하십시오.

noSuchMethod()

코드가 존재하지 않는 메서드 나 인스턴스 변수를 사용하려고 할 때마다 감지하거나 반응하려면 noSuchMethod()를 재정의 할 수 있습니다.

class A {
  // Unless you override noSuchMethod, using a
  // non-existent member results in a NoSuchMethodError.
  
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}

다음 중 하나에 해당하지 않으면 구현되지 않은 메서드를 호출 할 수 없습니다.

  • 수신자는 동적 정적 유형을 갖습니다.

  • 수신기에는 구현되지 않은 메서드를 정의하는 정적 유형이 있고 (추상은 괜찮음) 수신기의 동적 유형에는 Object 클래스의 것과 다른 noSuchMethod() 구현이 있습니다.

자세한 내용은 비공식적 인 noSuchMethod 전달 사양을 참조하세요.

확장메서드

Dart 2.7에 도입 된 확장 메서드는 기존 라이브러리에 기능을 추가하는 방법입니다. 자신도 모르게 확장 메서드를 사용할 수 있습니다. 예를 들어 IDE에서 코드 완성을 사용하는 경우 일반 메서드와 함께 확장 메서드를 제안합니다.

다음은 string_apis.dart에 정의 된 parseInt()라는 문자열에 확장 메서드를 사용하는 예시입니다.

import 'string_apis.dart';
...
print('42'.padLeft(5)); // Use a String method.
print('42'.parseInt()); // Use an extension method.

확장 메서드 사용 및 구현에 대한 자세한 내용은 확장 메서드 페이지를 참조하세요.

열거 타입

종종 열거 타입 또는 열거 형이라고 하는 열거 타입은 고정 된 수의 상수 값을 나타내는 데 사용되는 특수한 종류의 클래스입니다.

열거 타입 사용

enum 키워드를 사용하여 열거 타입을 선언합니다.

enum Color { red, green, blue }

열거 타입의 각 값에는 열거 타입 선언에서 값의 0부터 시작하는 위치를 반환하는 인덱스 getter가 있습니다. 예를 들어 첫 번째 인덱스 값은 0이고 두 번째 인덱스 값은 1입니다.

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

열거 타입의 모든 값 목록을 가져 오려면 열거 타입의 값 상수를 사용합니다.

List <Color> 색상 = Color.values;
assert (colors [2] == Color.blue);

switch에서 열거 타입을 사용할 수 있으며 열거 타입의 모든 값을 처리하지 않으면 경고가 표시됩니다.

var aColor = Color.blue;

switch (aColor) {
  case Color.red:
    print('Red as roses!');
    break;
  case Color.green:
    print('Green as grass!');
    break;
  default: // Without this, you see a WARNING.
    print(aColor); // 'Color.blue'
}

열거 타입에는 다음과 같은 제한이 있습니다.

  • 열거 타입을 하위 클래스 화하거나 혼합하거나 구현할 수 없습니다.
  • 열거 타입을 명시 적으로 인스턴스화 할 수 없습니다.

자세한 내용은 Dart 언어 사양을 참조하세요.

클래스에 기능 추가 : mixins

믹스 인은 여러 클래스 계층에서 클래스의 코드를 재사용하는 방법입니다.

믹스 인을 사용하려면 with 키워드 다음에 하나 이상의 믹스 인 이름을 사용하십시오. 다음 예제는 믹스 인을 사용하는 두 개의 클래스를 보여줍니다.

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

믹스 인을 구현하려면 Object를 확장하고 생성자를 선언하지 않는 클래스를 만듭니다. mixin을 일반 클래스로 사용하려면 class 대신 mixin 키워드를 사용하십시오. 예를 들면,

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

특정 유형 만 mixin을 사용할 수 있도록 지정하려면 (예: mixin이 정의하지 않은 메소드를 호출 할 수 있도록) on을 사용하여 필수 수퍼 클래스를 지정하십시오.

mixin MusicalPerformer on Musician {
  // ···
}

mixin 키워드에 대한 지원은 Dart 2.1에서 도입되었습니다. 이전 릴리스의 코드는 일반적으로 추상 클래스를 대신 사용했습니다. 2.1 믹스 인 변경에 대한 자세한 내용은 Dart SDK 변경 로그2.1 믹스 인 사양을 참조하세요.

클래스 변수 및 메서드

static 키워드를 사용하여 클래스 전체 변수 및 메서드를 구현합니다.

정적 변수

정적 변수 (클래스 변수)는 클래스 전체 상태 및 상수에 유용합니다.

class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

정적 변수는 사용될 때까지 초기화되지 않습니다.

이 페이지는 상수 이름에 대해 lowerCamelCase를 선호하는 스타일 가이드 권장 사항을 따릅니다.

정적 메서드

정적 메서드 (클래스 메서드)는 인스턴스에서 작동하지 않으므로 이에 대한 액세스 권한이 없습니다. 예를 들면,

import 'dart:math';

class Point {
  double x, y;
  Point(this.x, this.y);

  static double distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

일반적이거나 널리 사용되는 유틸리티 및 기능에 대해 정적 메서드 대신 최상위 수준 함수를 사용하는 것이 좋습니다.

정적 메서드를 컴파일 타임 상수로 사용할 수 있습니다. 예를 들어 정적 메서드를 상수 생성자에 매개 변수로 전달할 수 있습니다.

profile
Javascript로 많은 것을 쉽고 빠르고 재밌게 만드는 것을 좋아합니다.

0개의 댓글