Reason-BasicTypeIII

Basic Type

今天討論的東西會也很多(每天啃到天荒地老)

  • Reason - Record
  • Reason - Object
  • Reason - Destructuring

Reason - Record

Reason - Record 很像 Javascript 的 Object

但是他有幾個特性

  • 更輕量
  • 預設是不可改變的 (Immutable)
  • 欄位名稱和型別都是固定的
  • 很快
  • 是較嚴格的類別

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
type person = {
age: int,
name: string
};

let tomas = {
age: 35,
name: "Tomas Lin"
};

let tomasName = tomas.name;
print_endline(tomasName); /* Tomas Lin */

需要明確的定義類型跟結構

Record 需要先宣告一個基本的結構 (Type)

否則會報錯

如果符合則會自動型別推導

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type person = {
age: int,
name: string
};

let tomas: person = {
age: 35,
name: "Tomas Lin"
};

let tomasName = tomas.name;
print_endline(tomasName);
let simon = {
age: 22,
name: "Simon"
};

上面的範例中 tomas 有指定型別是 person

但是 simon 並未指定,可是因為他的結構和 person 一樣

所以 Reason 會自動做型別推導為 person

note:若是有兩個同樣型別結構的話則會依據較近的型別

你也可以將型別宣告在別的檔案中

但是需要明確的指定名稱

AnimalType.re

1
type cat = {color: string, call: string};

Animal.re

1
2
3
4
5
6
let whiteCat: AnimalType.cat = {
color: "white",
call: "喵!"
};

print_endline(whiteCat.call);

Spread 修改 (immutable update)

因為 Record 是不可以直接修改的

可以利用 Spread 來做修改的實作

範例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type person = {
age: int,
name: string
};

let tomas: person = {
age: 35,
name: "Tomas Lin"
};

let tomasName = tomas.name;
print_endline(tomasName);
let simon = {
age: 22,
name: "Simon"
};

let tomasNextYear = {...tomas, age: tomas.age + 1};

Js.log(tomasNextYear.age);/* 36 */

注意:Spread修改不能夠增加新的欄位

mutable update

Reason 也保有直接修改的彈性

範例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type person = {
age: int,
mutable name: string
};

let tomas: person = {
age: 25,
name: "Tomas Lin"
};

let name = "Simon";

let simon = {
age: 25,
name
};

tomas.age = tomas.age + 1;

Js.log(tomas.age); /* 26 */
Js.log(simon.name); /* Simon */

也支援 punning 簡化程式碼

不能用 Record 處理的問題

Reason 中你無法宣告一個 function 他的參數傳入一個物件

這個物件中必要參數是 age

而其他參數都是可以變動的

範例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type person = {age: int, name: string};
type monster = {age: int, hasTentacles: bool};

let getAge = (entity) => entity.age;
let kraken = {age: 9999, hasTentacles: true};
let me = {age: 5, name: "Baby Reason"};

getAge(kraken);
getAge(me);
/* get Error:
This has type:
person
But somewhere wanted:
monster */

Type system 不能定義一個類型是 personmonster

當你有這類型需求的話

接下來介紹的 Reason - Object 可以滿足

Reason - Object

有些時候 Reason - Record 無法滿足一些特殊情境的需求

所以便有了 Reason - Object 增加一些彈性

型別

物件不一定要宣告型別

看起來和 Reason - Record 十分相似

除了 ...

範例如下

1
2
3
4
type tesla = {
.
color: string
};

開頭 . 代表這是一個閉鎖的物件

任何基於這個型別的物件都必須完全符合結構

1
2
3
4
type car(`a) = {
..
color: string
} as `a;

開頭 .. 則代表這是開放型的物件,所以可以包含其他值或 function

開放型的物件代表是多型

所以需要一個參數

Example

Simple

1
2
3
4
5
6
7
8
9
10
11
type tesla = {
.
color: string,
};

let obj: tesla = {
val red = "Red";
pub color = red;
};

Js.log(obj#color) /* "Red" */

在這個物件中含有兩個屬性

私有屬性 redcolor method

因為 color 是一個公開的 method

所以我們可以利用 object notation 來標記取得值

物件只導出Method,所有屬性都是Private的

Advanced

1
2
3
4
5
6
7
8
9
10
11
12
type tesla = {.
drive: (int) => int
};

let obj: tesla = {
val hasEnvy = ref(false);
pub drive = (speed) => {
this#enableEnvy(true);
speed;
};
pri enableEnvy = (envy) => hasEnvy := envy
};

在這個範例中 tesla 中一個公開的 drive 也有一個私有的 enableEnvy method

私有的 method 只可以在物件內部取用

Reason 也有 this 和 Javascript 的 this 不一樣的地方在於

Reason 的 this 永遠都會指向物件本身

開放式物件的範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type tesla('a) = {
..
drive: int => int
} as 'a;

type teslaParams = {.
drive: int => int,
doYouWant: unit => bool
};

let obj: tesla(teslaParams) = {
val hasEnvy = ref (false);
pub drive = (speed) => {
this#enableEnvy(true);
speed;
};
pub doYouWant = () => hasEnvy^;
pri enableEnvy = (envy) => hasEnvy := envy
};

Js.log(obj#doYouWant());
Js.log(obj#drive(11));
Js.log(obj#doYouWant());

上面的 tesla 中為開放型物件

但是需要有一個參數 teslaParams 定義所有開放的的 method

但是如果你要找由 Javascript 的物件,你需要的不是 Reason - Object

而是特別的 BukleScript - Record special Record

Reason - Destructuring (解構)

解構是很清楚簡單的方式來取得物件或陣列中的變數

用法

下面綁定 ten = 10twenty = 20

1
2
3
4
let someInts = (10, 20);
let (ten, twenty) = someInts;
Js.log(ten);
Js.log(twenty);

下列綁定變數 name = "Guy"age = 30

1
2
3
4
5
type person = {name: string, age: int};
let somePerson: person = {name: "Tomas", age: 30};
let {name, age} = somePerson;
Js.log(name);
Js.log(age);

取回變數後可以重新命名

1
2
3
4
5
type person = {name: string, age: int};
let somePerson: person = {name: "Tomas", age: 30};
let {name: n, age: a} = somePerson;
Js.log(n);
Js.log(a);

也可以定義型態

1
2
3
4
5
type person = {name: string, age: int};
let somePerson: person = {name: "Tomas", age: 30};
let {name: (n: string), age: (a: int)} = somePerson;
Js.log(n);
Js.log(a);

當然函式的標籤式參數也可以解構

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type person = {
name: string,
age: int
};

let tomas = {name: "Tomas", age: 25};

let someFunction = (~person as {name}) => {
Js.log(name);
};

let otherFunction = (~person as {name} as thePerson) => {
Js.log(thePerson);
Js.log(name);
};

someFunction(~person=tomas);
otherFunction(~person=tomas);

Mutable

有時候我們會需要可以變更的變數

Reason 也有保留這部分的彈性

1
2
3
4
type total = ref(int);
let x: total = ref(5);
x := x^ + 1;
Js.log(x); // 6

ref 只是一個語法糖

透過 := 修改

^ 代表取出他的值

這樣就可以簡單地在 Reason 中使用 Mutation 的技巧

文章目录
  1. 1. Basic Type
    1. 1.1. Reason - Record
      1. 1.1.1. 基本使用
      2. 1.1.2. 需要明確的定義類型跟結構
      3. 1.1.3. Spread 修改 (immutable update)
      4. 1.1.4. mutable update
      5. 1.1.5. 不能用 Record 處理的問題
    2. 1.2. Reason - Object
      1. 1.2.1. 型別
      2. 1.2.2. Example
        1. 1.2.2.1. Simple
        2. 1.2.2.2. Advanced
        3. 1.2.2.3. 開放式物件的範例
    3. 1.3. Reason - Destructuring (解構)
      1. 1.3.1. 用法
      2. 1.3.2. Mutable
|