使用ReasonML变得合理-第3部分
模式匹配,类型参数,异常,循环,模块和BuckleScript
这是一个分为3部分的系列文章的 第2 部分 ,我将帮助您理解ReasonML及其所有语法和语义。 我将介绍从基本数据类型到在ReasonML中声明函数的所有内容。
在继续之前,请确保您已阅读本系列的第1部分和第2部分 。 它们都已连接。
使用开关进行模式匹配
模式匹配是该语言的最佳功能之一。 它主要做两件事:
- 检查值的特定结构。
- 提取值的一部分。
使用模式匹配,我们可以做很多很棒的事情,例如将多个模式传递到一个案例中!
由于结构相等,模式匹配可以很好地与元组,列表,变体和记录等数据结构配合使用。
模式匹配元组
# switch (rajat) {
| ("Learn ReasonML", false) => "It's Awesome"
| ("Learn ReasonML", true) => "It really is awesome"
};
但这将使我们的应用程序面面俱到。 我们需要使用_
来匹配此类型的不匹配值。 使用名称而不是下划线允许我们提取部分元组。
# switch (rajat) {
| (_, true) => "Its Awesome"
| (text, false) => "It really is awesome. " ++ text
};
- string = "It really is awesome. Learn ReasonML"
模式匹配列表
对于列表,我们可以在精确列表上执行模式匹配。
# switch (["a", "b", "c"]) {
| ["a", "b", "c"] => true
| _ => false
};
关于与列表进行模式匹配的最好的事情是...
可用于提取列表的第一个和最后一个元素。
# switch (["x", "y", "z"]) {
| [head, ...tail] => print_endline(head)
| [] => print_endline("Empty list")
};
模式匹配数组
模式匹配数组时,我们只能对特定长度的数组执行此操作。 数组中的值使用结构相等性进行匹配。 我们可以使用下划线,也可以使用名称提取数组元素。
# switch ([|"a", "b", "c"|]) {
| [|"a", "b", _|] => print_endline("a, b and something")
| [|_, "x", "y"|] => print_endline("something, " ++ x ++ y)
| _ => print_endline("An Array")
};
模式匹配记录
首先,我将通过声明类型创建一个记录,然后将其绑定到name
。
# type todo = { text: string, checked: bool};
# let myTodo = { text: "Learn ReasonML", checked: true};
现在,我可以通过匹配精确值来提取文本。 但是,我将尝试其他方法并使用名称描述提取文本。
# switch (myTodo) {
| {text, checked: true} => "It is awesome: " ++ text
| {text, checked: false} => "You won't regret it!" ++ text
};
- : string = "It is awesome: Learn ReasonML"
模式匹配变体
让我们创建一个带有标签DC
和Marvel
名为hero
的变体。
# type hero = DC(string) | Marvel(string);
# let dc = DC("Batman");
# let marvel = Marvel("Iron Man");
使用模式匹配,我可以检查标签并提取变体的任何部分。
# switch (dc) {
| DC(text) => "I am " ++ text
| Marvel(text) => "I am " ++ text
};
- : string = "I am Batman"
如果要匹配多个项目并返回结果,可以执行以下操作:
# switch ("Batman") {
| "Superman" | "Batman" | "The Flash" => "DC Comics"
| _ => "Marvel Comics"
};
- : string = "DC Comics"
类型参数
类型也可以接受参数。 可以将参数与其他语言的泛型进行比较。 创建列表时,首先需要创建一个接收数据类型的类型列表。 在此,数据类型是类型参数。
# let rajat: list(string) = ["Batman", "Superman"];
编译器甚至可以反转列表的类型参数。
但是为什么我们需要这个呢?
使用类型参数,我们可以创建一个新类型,该类型可以接受任意数量的参数。
基本上, type
可以变成接受参数并返回新类型的函数。
# type hero('a) = ('a, 'a);
# let heroOne: hero(string) = ("Superman", "Clark Kent");
这样,我们可以在创建更多类型时避免重复。
还要注意,类型参数仅在以“`”开头,后跟字符或单词的情况下才有效。
let绑定中的可变性
let
绑定默认是不可变的。 一旦绑定引用了一个值,就不能引用其他任何内容。 但是,您可以通过创建一个具有相同名称的新绑定并遮盖以前的绑定来避免此问题。
# let person = "Clark Kent";
# print_endline(person); /* Prints "Clark Kent" */
# let person = "Superman";
# print_endline(person); /* Print "Superman" */
还有一种方法可以通过使用引用包装实际值来使let
绑定可变。
# let foo = ref(5);
let foo: ref(int) = {contents: 5};
现在,如果我想更改foo
内部的数据,这就是我将要做的:
# foo := 6;
- : unit = ()
# foo;
- : ref(int) = {contents: 6}
foo
的值从5更改为6。要检索引用的值,我需要使用^
字符。
# foo^;
- : int = 6
例外情况
在Reason中,Exception是您尝试在空列表中查找内容时得到的一种变体。
# List.find(x => x == "Rajat", []);
Exception: Not_found.
那不是全部! 您可以使用raise
函数创建自己的异常。 要在您的应用程序中捕获异常,请使用模式匹配。
# raise(Not_found);
Exception: Not_found.
# try (raise(Not_found)) {
| Not_found => "Oh Oh!"
};
= : string = "Oh Oh!"
我们可以使用exception
直接在switch
表达式中匹配exception
。
# switch (List.find(x => x == "rajat", [])) {
| name => "Obtained"
| exception Not_Fount => "Not found"
};
- : string = "Not found"
# switch (List.find(x => x == "rajat", ["rajat"])) {
| item => "Obtained"
| exception Not_found => "Not found"
};
- : string = "Obtained"
exception
用途不多。 实际上,您可以改为使用option
。
循环
对于循环
for
循环用于从数据结构的第一个值到最后一个值进行迭代。
# for (x in 1 to 5) {
print_int(x * 2);
print_string(" ");
};
2 4 6 8 10 - : unit = ()
该范围必须有效,并且必须从较低的值变为较高的值。 如果你尝试做它的其他方式, for
什么都不会做。 为了for
在反方向工作,更换to
与downto
。
While循环
只要给定条件为true
, while
循环将保持运行。
# let x = ref(0);
let x: ref(int) = { contents: 0};
# while (x^ < 5) {
print_int(x^);
x := x^ + 1;
};
01234- : unit = ()
模组
在您的代码中,模块可以描述为小块。 它们使我们能够将诸如let
绑定和types
东西封装到逻辑实体中。
Reason中的每个文件都是一个模块。 这就是为什么name
在每个项目中都必须唯一的原因。
使用module
关键字在您的Reason项目中创建一个模块。 确保模块名称大写。
# module Rajat = {};
`module Math` : { };
# module Math = {
let name = "rajat";
let age = 24;
};
`module Math`: { let name: string; let age: int };
要访问模块内部的任何内容,请使用.
符号。
# Rajat.name;
- : string = "rajat"
# Rajat.age;
- : int = 24;
.
符号在这里确实很有用,因为我们也可以访问存储在模块内部的类型。 这样,编译器将仅查看当前模块或其父模块。
Reason还允许我们在不加模块名称的情况下打开模块的定义并引用其内容。
为此,我们使用open
关键字。 这将全局打开模块并将其定义导入当前作用域。
BuckleScript
返回第1部分 在本系列文章中,我曾经说过可以使用称为BuckleScript的东西将Reason编译成JavaScript 。 让我们看看这是如何完成的。
首先,我们需要将BuckleScript安装到我们的系统中。
npm install -g bs-platform
安装此软件包后,我不仅可以将代码编译为JavaScript,还可以将其编译为本地二进制代码。
现在我需要使用bs-platform
建立一个新项目
bsb -init reason-project -theme basic-reason
该命令将在您的系统中创建一个新的目录,名为reason-project
。 如果查看此目录的内容,您会发现它与典型的JavaScript项目有一些相似之处。
这里唯一的独特之处是bsconfig.json
文件。 该文件是我们可以为此项目配置BuckleScript的位置。
如果查看此项目的src
目录,将会看到它包含一个Demo.re
文件。 让我们删除它并创建一个名为Main.re
的新文件。 您可以在此处编写任何ReasonML代码,并使用NPM / Yarn运行build
脚本。 这会将所有扩展名为.re
文件编译为匹配的JavaScript文件。 因此,我们的Main.re
文件将编译为Main.bs.js
您可以使用node
运行此JavaScript文件。
node src/Main.bs.js
您也可以使用start
脚本手动构建它。 该脚本将监视文件更改并相应地进行编译。
下一步是什么?
这个系列应该足以让您开始使用ReasonML。 但是,如果您仍然想了解更多信息,请在此处查看Reason的官方文档:
您还可以查看Nik Graf的Egghead课程。 这对我帮助很大!
我是GeekyAnts的技术内容作家RajatS 。 有抱负的编码员,任重道远。 热爱漫威电影的死硬DC漫画迷。 以多任务处理而闻名。
感谢您的阅读,希望对您有所帮助! 如果您喜欢此帖子,请and,然后在此处和/或在Twitter上关注我,以随时了解我的新帖子!
From: https://hackernoon.com/get-reason-able-with-reasonml-part-3-6e2f3f61f959