Dart-02: Language Tour
Dart-02-01   Important concepts
Dart-02-02   Keywords
Dart-02-03   Variables
Dart-02-04   Built-in types
Dart-02-05   Functions
Dart-02-06   Operators
Dart-02-07   Control flow statements
Dart-02-08   Exceptions
Dart-02-09   Classes
Dart-02-10   Generics
Dart-02-11   Libraries and visibility
Dart-02-12   Asynchrony support
Dart-02-13   Generators
Dart-02-14   Callable classes
Dart-02-15   Isolates
Dart-02-16   Typedefs
Dart-02-17   Metadata
Dart-02-18   Comments

Operators

Dart - Functions

Dart는 다음 표에 표시된 연산자를 지원한다. 이러한 연산자 중 많은 부분을 class member로 구현할 수 있다.

Description   Operator
unary postfix   expr++ expr-- () [] ?[] . ?. !
unary prefix   -expr !expr ~expr ++expr --expr await expr
multiplicative   * / % ~/
additive   + -
shift   << >> >>>
bitwise AND   &
bitwise XOR   ^
bitwise OR   |
relational and type test   >= > <= < as is is!
equality   == !=
logical AND   &&
logical OR   ||
if null   ??
conditional   expr1 ? expr2 : expr3
cascade   .. ?..
assignment   = *= /= += -= &= ^= etc.

연산자를 사용할 때 expression을 만든다. 다음은 연산자 expression의 몇 가지 예이다:

a++
a + b
a = b
a == b
c ? a : b
a is T

연산자 table에서, 각 연산자는 뒤에 오는 행의 연산자보다 우선 순위가 높다. 예를 들어, multiplicative 연산자 %는 equality 연산자 == 보다 높은 우선순위를 가진다(따라서 이전에 실행된다.) 또 이 연산자는 logical AND 연산자 && 보다 높은 우선순위를 가진다. 이 우선 순위는 다음 두 줄의 코드가 동일한 방식으로 실행됨을 의미한다.

// Parentheses improve readability.
if ((n % i == 0) && (d % i == 0)) ...

// Harder to read, but equivalent.
if (n % i == 0 && d % i == 0) ...

두 개의 피연산자를 사용하는 연산자의 경우, 맨 왼쪽 피연산자가 사용되는 방법을 결정한다. 예를 들어 Vector 객체와 Point 객체가 있는 경우, aVector + aPointVector addition(+)를 사용한다.

1. Arithmetic operators

Dart는 다음 표와 같이 일반적인 산술 연산자를 지원한다.

Operator   Meaning
+   Add
-   Subtract
-expr   Unary minus, negation
(reverse the sign of the expression)
*   Multiply
/   Divide
~/   Divide, returning
an integer result
%   Get the remainder of
an integer division(modulo)

예시:

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2);  // Result is an int
assert(5 % 2 == 1);   // Remainder

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

Dart는 또한 접두사 및 접미사 증가 및 감소 연산자를 모두 지원한다.

Operator   Meaning
++var   var = var + 1
(expression value is var + 1)
var++   var = var + 1
(expression value is var)
--var   var = var - 1
(expression value is var - 1)
var--   var = var - 1
(expression value is var)

예시:

int a;
int b;

a = 0;
b = ++a;  // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++;  // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a;  // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--;  // Decrement a AFTER b gets its value.
assert(a != b);  // -1 != 0

2. Equality and relational operators

Operator   Meaning
==   Equal; see discussion below
!=   Not equal
>   Greater than
<   Less than
>=   Greater than or equal to
<=   Less than or equal to

두 객체 x와 y가 같은 것을 나타내는지 test 하려면 == 연산자를 사용한다. (드물게 두 객체가 정확히 같은 객체인지 알아야 하는 경우, identical() 함수를 사용한다.) == 연산자 작동 방식은 다음과 같다.

  1. x 또는 y가 null인 경우, 둘 다 null이면 true를 return 하고, 하나만 null이면 false를 return 한다.
  2. argument y를 사용하여 x에서 == method를 호출한 결과를 return 한다. (==와 같은 연산자는 첫 번째 피연산자에서 호출되는 method이다.)

다음은 equality와 relational 연산자를 각각 사용하는 예이다:

assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

3. Type test operators

as, is, is! 연산자는 runtime에 type을 확인하는 데 편리하다.

Operator   Meaning
as   Typecast (also used to specify library prefixes)
is   True if the object has the specified type
is!   True if the object doesn’t have the specified type

objT에서 지정한 interface를 구현하는 경우, obj is T의 결과는 true이다. 예를 들어, obj is Object?는 항상 true이다.

객체가 해당 type인 것이 확실한 경우에만, as 연산자를 사용하여 객체를 특정 type으로 cast 한다. 예시:

(employee as Person).firstName = 'Bob';

객체가 T type인지 확실하지 않은 경우, 객체를 사용하기 전에 is T를 사용하여 type을 확인한다.

if (employee is Person) {
  // Type check
  employee.firstName = 'Bob';
}

code는 동일하지 않다. employee가 null이거나 Person이 아니면, 첫 번째 예시는 예외를 throw하지만 두 번째는 그렇지 않다.

4. Assignment operators

이미 보았듯이, = 연산자를 사용하여 값을 할당할 수 있다. 할당 대상 변수가 null인 경우에만, 할당하려면 ??= 연산자를 사용한다.

// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;

+=과 같은 복합 할당 연산자는 연산을 할당과 결합한다.

         
= *= %= >>>= ^=
+= /= <<= &= |=
-= ~/= >>=    

복합 할당 연산자의 작동 방식은 다음과 같다.

    Compound assignment   Equivalent expression
For an operator op:   a op= b   a = a op b
Example:   a += b   a = a + b

다음 예제에서는 할당 및 복합 할당 연산자를 사용한다.

var a = 2;  // Assign using =
a *= 3;     // Assign and multiply: a = a * 3
assert(a == 6);

5. Logical operators

Operator   Meaning
!expr   inverts the following expression
(changes false to true, and vice versa)
||   logical OR
&&   logical AND

다음은 논리 연산자를 사용하는 예이다:

if (!done && (col == 0 || col == 3)) {
  // ...Do something...
}

6. Bitwise and shift operators

Operator   Meaning
&   AND
|   OR
^   XOR
~expr   Unary bitwise complement
(0s become 1s; 1s become 0s)
<<   Shift left
>>   Shift right
>>>   Unsigned shift right

다음은 bit 및 shift 연산자를 사용하는 예이다:

final value = 0x22;
final bitmask = 0x0f;

assert((value & bitmask) == 0x02);  // AND
assert((value & ~bitmask) == 0x20);  // AND NOT
assert((value | bitmask) == 0x2f);  // OR
assert((value ^ bitmask) == 0x2d);  // XOR
assert((value << 4) == 0x220);  // Shift left
assert((value >> 4) == 0x02);  // Shift right
assert((value >>> 4) == 0x02);  // Unsigned Shift right
assert((-value >> 4) == -0x03);  // Shift right
assert((-value >>> 4) > 0);  // Unsigned Shift left

>>> 연산자(triple-shift 또는 unsigned shift라고 함)에는 최소 2.14의 language version이 필요하다.

7. Conditional expressions

Dart에는 if-else문이 필요할 수 있는 expression을 간결하게 평가할 수 있는 두 개의 연산자가 있다.

condition ? expr1 : expr2: 조건이 참이면 expr1의 값을 평가하고 그 값을 return 한다. 조건이 거짓이면 expr2의 값을 평가하고 그 값을 return 한다.

expr1 ?? expr2: expr1이 null이 아니면 그 값을 return 한다. expr1이 null이면 expr2의 값을 평가하고 그 값을 return 한다.

boolean expression을 기반으로 값을 할당해야 하는 경우, ?:의 사용을 고려한다:

var visibility = isPublic ? 'public' : 'private';

boolean expression이 null에 대해 test하는 경우, ??의 사용을 고려한다:

String playerName(String? name) => name ?? 'Guest';

이전 예제는 적어도 두 가지 다른 방법으로 작성되었을 수 있지만, 간결하지는 않다.

// Slightly longer version uses ?: operator.
String playerName(String? name) => name != null ? name : 'Guest';

// Very long version uses if-else statement.
String playerName(String? name) {
  if (name != null) {
    return name;
  } else {
    return 'Guest';
  }
}

8. Cascade notation

Cascades(.., ?..)는 동일한 객체에 대해 일련의 작업을 수행할 수 있게 해준다. 함수 호출 외에도 동일한 객체의 field에 접근할 수도 있다. 이렇게 하면 임시 변수를 생성하는 단계를 줄일 수 있고, 보다 유동적인 코드를 작성할 수 있다.

var paint = Paint()
  ..color = Colors.black
  ..strokeCap = StrokeCap.round
  ..strokeWidth = 5.0;

생성자 Paint()Paint 객체를 return 한다. Cascade 표기법을 따르는 code는, return 될 수 있는 값을 무시하고 이 객체에서 작동한다.

이전 예제는 다음 코드와 동일하다.

var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;

cascade가 작동하는 객체가 null일 수 있는 경우, 첫 번째 작업에 null-shorting cascade (?..)를 사용한다. ?..로 시작하면 해당 null 객체에 대해 cascade 연산이 시도되지 않음을 보장한다.

querySelector('#confirm') // Get an object.
  ?..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

?.. syntax는 2.12 이상의 language version이 필요하다.

이전 코드는 다음과 동일하다:

var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.conClick.listen((e) => window.alert('Confirmed!'));

cascade를 중첩할 수도 있다. 예를 들어:

final addressBook = (AddressBookBuilder()
    ..name = 'jenny'
    ..email = 'jenny@example.com'
    ..phone = (PhoneNumberBuilder()
        ..number = '415-555-0100'
        ..label = 'home')
      .build())
  .build();

실제 객체를 return 하는 함수에서 cascade를 구성할 때 주의해야 한다. 예를 들어 다음 코드는 실패한다:

var sb = StringBuffer();
sb.write('foo')
  ..write('bar'); // Error: method 'write' isn't defined for 'void'.

sb.write() 호출은 void를 return 하고, void에서는 cascade를 구성할 수 없다.

엄밀히 말하면, cascade에 대한 “double dot” 표기법은 연산자가 아니다. 이것은 Dart syntax의 일부일 뿐이다.

9. Other operators

다른 예에서 나머지 연산자의 대부분을 보았다:

() - Function application: 함수 호출을 나타낸다.

[] - Subscript access: overriding이 가능한 [] 연산자의 호출을 나타낸다. 예를 들어, fooList[1]은 index 1의 element에 접근하기 위해서 fooList1을 전달한다.

?[] - Conditional subscript access: []와 비슷하지만, 맨 왼쪽 피연산자는 null일 수 있다. 예를 들어, fooList?[1]fooList가 null이 아닐 경우에 index 1의 element에 접근하기 위해서 fooList1을 전달한다.

. - Member access: expression의 property를 나타낸다. 예를 들어, foo.bar는 expression foo에서 property bar를 선택한다.

?. - Conditional member access: .과 비슷하지만, 맨 왼쪽 피연산자는 null일 수 있다. 예를 들어, foo?.barfoo가 null이 아닐 경우에 expression foo에서 property bar를 선택한다.

! - Null assertion operator: non-nullable type으로 expression을 casting하고, casting이 실패하면 runtime 예외를 throw 한다. 예를 들어, foo!.barfoo가 null이 아님을 주장하고, bar property를 선택한다. 만약 foo가 null이면, runtime 예외가 throw 된다.

태그:

카테고리:

업데이트:

댓글남기기