# Dart - tutorial - before Flutter project

# var

Dart declares variables similarly to Java, but unlike Java, type inference is possible.

```dart
var friend = 'taelab';
friend = 23; // Error: Compilation failed.
```

By the way, Dart also has a dynamic type that can change its type.

# dynamic

In the case of dynamic, the type can be inferred like **var**, and the type can also be changed. In addition, since **dynamic** is supported in parameters, there is no need to specify the type.

```dart
dynamic a= 'tae';
a= 121342;
```

# Type casting and num

In Java, large types are automatically type-casted without explicitly type-casting small types, but in the case of Dart, type-casting is required.

```dart
int n = 2;
// Error: Compilation failed.
double m = n; 

int n = 1;
double m = n as double; //ok
```

In the case of int and double, they can also be declared as supertype ***num***.

```dart
num a = 1;
num b = 1.11;
```

# final / const

In common, both **final** and **const** cannot be changed once declared. A value defined as **final** can be set as a value defined at *runtime*, but a value defined as **const** cannot be set as a value defined at *runtime*.

## **Collections**

Dart provides collections such as **List, Map,** and **Set**, but does not provide an **array** data structure.

```dart
// List
List<int> setNums = [1,2,3,4,5];
var nums2 = [1, 2, 3]; // Type inferred
var nums3 = [1, 2, 3 ,4, if (true) 5]; //condition in List
var friends = ['a','b','c'];
var new_friends = ['d','e','f', for (var friend in friends ) "- ${friend}"];


// set
Set<int> setNums = {1,2,3,4,4,4,4,66,6};
var setNums2 = {1,5,5,4,6,4,3,3,5,5,5,1,5,5,2,2,2}; // Type inferred



// map
Map<String, int> mapNums = {
  "key" : 1,
  "key2" : 2
};
var mapNums2 = {  // Type inferred
  "key" : 1,
  "key2" : 2
};

var nums = {

}
```

When declaring **set** and **map** through **var**, if nothing is written inside {}, **var** is inferred as **map** type.

# Spread operator ...

```dart
  // (...)
  var a = [1,2,3,4,6];
  var b = [...a, 5, 7];
```

# function declaration

Since the type of the parameter is inferred as **dynamic**, there is no need to specify the data type.

```dart
add(num1, num2){

  return num1 + num2;
}
```

## optional parameter

Optional parameters allow optional use of parameters wrapped in {} when defining a function.

```dart
add(num1, {num2}){

  return num1 + num2;
}

print(add(1, num2 : 3));
```

If you want to return a value other than null as for optional parameter, you can give it a default value.

```dart
add(num1, {num2 = 3}){

  return num1 + num2;
}
```

# function and QQ operator

```dart
// name parameter can be null.
String capitalizeName(String? name) => name != null 
? name.toUpperCase() : 'ANON' 
```

```dart
String capitalizeName(String? name) => name?.toUpperCase() ?? 'ANON'
```

# QQ operator

```dart
void main () {
    String? name;
    name ??= 'a';
    name ?? ='another';
    print(name); // a
}
```

# Asynchronous processing - Future, async, await

A Future promises to receive the result of a certain task later, and proceeds to the next task immediately without waiting for the result of the requested task. After that, when the task is completed, the asynchronous processing is executed by receiving the result value.

```dart
void main(){
  
  print("start");
  asyncFunc();
  print("end");
}


Future asyncFunc() async{

  await Future.delayed(Duration(seconds : 1));
  print("1");
  
  await Future.delayed(Duration(seconds : 1));
  print("2");
  
  await Future.delayed(Duration(seconds : 1));
  print("3");

  return;
}
```

# Class

```dart
class Person {
  final String name = 'tat';
  int age;
  
  getName(){
    return name;
  }
    Person (String name, int age) {
        this.name = name; // error since final String field
         this.age = age;

    }
  
}
```

```dart
class Person {
  late final String name = 'tat';
    //late means that the values of the variables will be retrieved later.
  late int age; 
  
  getName(){
    return this.name;
  }
    Person (String name, int age) {
        this.name = name; 
         this.age = age;

    }
  
}
void main () {
    var person = Person ("taesik", 22);

}
```

## Brief constructor + specified parameter + required

```dart
class Player {
    final String name;
    int age;
    String team;
    int point;

    Player({
        required this.name,
        required  this.age,
        required this.team,
        required this.point,
    });
        
    
    void greet() {
        print('Hi my name is $name');
    
    }
    
}

void main() {
    //specified parameter key-value style 
    var player = Player (
        name:"asd",
        age: 22,
        team: 'pncst',
        point: 20000,
    )
}
```

## Brief field

```dart
class Player {
    final String name,  team;
    int age,point;
    

    Player({
        required this.name,
        required  this.age,
        required this.team,
        required this.point,
    });
        
    
    void greet() {
        print('Hi my name is $name');
    
    }
    
}

void main() {
    //specified parameter key-value style 
    var player = Player (
        name:"asd",
        age: 22,
        team: 'pncst',
        point: 20000,
    )
}
```

**<mark>late</mark>** means that the values of the variables will be retrieved later.

Java uses the new keyword when creating an object, but Dart basically omits it.

The same role as Private in Java, but in Dart, Private is defined by appending \_. In Java, private can be accessed only within the class, but in Dart, private variables can be accessed in the file where the class is defined.

## Named Constructors

```dart
class Player {
    final String name,  team;
    int age,point;
    

    Player( {
        required this.name,
        required this.age,
        required this.team,
        required this.point,
    }
    );
    Player.createBluePlayer({
        required String name,
         required int age
    }) :    this.age = age,
            this.name = name,
            this.team = 'blue',
            this.xp = 0; 

    Player.createRedPlayer(String name, int age) 
    : this.age =age,
    this.name = name,
    this.team = 'red',
    this.xp =0;
    
    void greet() {
        print('Hi my name is $name');
    
    }
    
}

void main() {
    //specified parameter key-value style 
    var player = Player (
        name:"asd",
        age: 22,
        team: 'pncst',
        point: 20000,
    )

    var player1 = Player.createBluePlayer(
        name: 'brian',
        age:21,
    );
    var redplayer = Player.createRedPlayer('tasdi',21);
    
}
```

## Cascade Notation

```dart
class Player {
    final String name,  team;
    int age,point;
    

    Player( {
        required this.name,
        required this.age,
        required this.team,
        required this.point,
    }
    );
    Player.createBluePlayer({
        required String name,
         required int age
    }) :    this.age = age,
            this.name = name,
            this.team = 'blue',
            this.xp = 0; 

    Player.createRedPlayer(String name, int age) 
    : this.age =age,
    this.name = name,
    this.team = 'red',
    this.xp =0;
    
    void greet() {
        print('Hi my name is $name');
    
    }
    
}

void main() {
    var taesik = Player(name: 'taesik', point:1000, age:22,team:'ada')
    ..name = 'asd'
    ..xp = 1200000
    ..team = 'blue';
    
    var ted = Player(name: 'taesik', point:1000, age:22,team:'ada');
    var clone = ted
    ..name = 'clone'
    ..xp = 12222
    ..team = 'blue'
    ..greet();
}
```

## enums

```dart
enum Team {red,blue}

// 
Team.blue
TEam.red
```

## abstract class, abstract method

```dart
abstract class Human {
    void walk;
        
}
class Player extends Human {
    void walk() {
        ...
    }
 ...
```

## Inheritance + override method

```dart
class Human {
    final String name;
    Human(this.name);
    void greet() {
        print('hello');
    }
}
enum Team {red,blue}

class Player extends Human {
    final Team team;
    Player({
        required this.team,
        required String name, //Forwarding to Human class
    }) : super(name:name);

    @override
    void sayHello(){
        super.sayHello();
        print('and I want to win ${team}');
    }
...
```

## Mixins - (Class without constructor)

```dart
class Point {
    final double level = 12121;

}
class QuickPlayer {
    void doSomethingQuick() {
        
    }
}

class Player with Point, QuicPlayer {
    ...
}
```

# null safety - nullable, non-nullable

```dart
int a = 10;
a = null; // Error: Compilation failed.

int? h = 10;
h = null; // ok
```

A **var** type cannot be declared nullable. As explained above, type inference is possible for var types, so nullable and non-nullable are automatically inferred.

**Null safety** in **dynamic** types is meaningless. The dynamic type means that the value to be assigned is not limited, and all types of data can be assigned. Since all of these types also include nullable, being declared as a dynamic type is itself declared as **nullable**.

# Type check - 'is'

```dart
  int a = 1;
  print(a is int); //true
  print(a is! int); //false
```

# anonymous function

```dart
(number) {
return number % 2 == 0;
};
```

# Lambda

```dart
(number) => number%2 == 0;
```

# typedef (type variable)

```dart
typedef listOfInts = List<int>;

listOfInts reverseListOfNumbers(listOfInts  list) {
    var reversed = list.reversed;
    return reversed.toList(); 
}
```
