上一节,我们学习了《环境搭建篇》,本篇将学习基础语法,默认所有的工具已经准备就绪中。
本文建议大家使用SublimeText 3.0,不仅界面清爽美观,而且功能强大好用。
一 、全世界通用的“Hello World”。
打开Demo\EX01_HelloWorld.carb,将会显示如下图一样的程序代码。
上图中的代码,各部分解释如下:
1)用 /* */包起来的,是注释部分,注释是给人看的,机器编译的时候,会忽略这部分代码
2)import system; 这是让编译器导入库文件(注:库文件也是Crab格式的源代码文件)
3)main {} 这是主程序,开发者写的程序代码,将从这里开始执行。
4)Print(‘Hello World’); 这一句,是在日志控制台上打印一句’Hello World’;
我们先不管代码是怎么样写的,而是先运行一下,看看效果。
打开CrabStudio。
1)点击“连接”按钮,如果连接成功,下面窗口会出现连接后的设备信息。
2)点击“打开”,选择Demo\EX01_HelloWorld.carb这个文件。
3)点击“编译”,将会出现如下图所示。
4)点击“下载”,将编译后的程序下载到开发板上。
5)点击“运行”,下方窗口将会切换到“Term”页面,并显示”Hello World“
这表示,我们的第一个程序,已经完美运行成功。
接下来,我们开始学习CRAB语言的语法部分。
二、基本语法
1)注释
注释是用于解释代码。编译器会忽略注释的条目。和大多数C系(C/C#/C++)语言相似,在 CRAB 程序中,多行注释以 /* 开始,并以字符 */ 终止,如下所示:
/*========================================This is a simple DEMO program, it send
a greeting of “Hello World” to the computer.
这是一个最简单的DEMO程序,它向你发送一个 “Hello World” 的问候。 ========================================*/ |
单行注释是用 ‘//’ 符号表示,常用于行尾。例如:
Print(‘Hello World’); //发送“Hello World”问候。 |
2)标识符
- 标识符是用来识别变量名、函数、类、接口或任何其它用户定义的项目。在 CRAB 中,标识符的命名必须遵循如下基本规则:
- 标识符必须以字母开头,后面可以跟一系列的字母、数字( 0 – 9 )或下划线( _ )。标识符中的第一个字符不能是数字。
- 标识符必须不包含任何嵌入的空格或符号,比如 ? – +! @ # % ^ & * ( ) [ ] { } . ; : ” ‘ / \。但是,可以使用下划线( _ )。
- 标识符不区分大小写。大写字母和小写字母都认为是相同的字母。
- 标识符可以使用中文名称,比如:名称,我是中文变量
- 标识符不能是 CRAB 关键字。(注:请参阅文章最后的关键字表格)
保留关键字 | ||||||
and | as | boolean | break | case | catch | class |
const | continue | crab | default | debug | do | double |
else | enum | event | extern | false | finally | for |
foreach | helper | if | import | in | interface | is |
long | new | not | null | object | or | out |
override | params | private | protected | public | property | refer |
return | repeat | sizeof | static | string | struct | switch |
this | throw | true | try | typeof | until | var |
virtual | void | while | xor |
3)值类型
值类型变量可以直接分配给一个值。值类型直接包含数据。比如 int、char、float,它们分别存储数字、字母、浮点数。当您声明一个 int 类型时,系统分配内存来存储值。
下表列出了 CRAB 中可用的值类型:
类型 | 描述 | 范围 | 默认值 |
boolean | 布尔值 | True 或 False | False |
byte | 8 位无符号整数 | 0 到 255 | 0 |
char | 8位 单个字符 | 0到255 | ‘\0’ |
tiny | 8 位有符号整数 | -127到127 | 0 |
short | 16 位有符号整数类型 | -32,768 到 32,767 | 0 |
ushort | 16 位无符号整数类型 | 0 到 65,535 | 0 |
int | 32 位有符号整数类型 | -2,147,483,648 到 2,147,483,647 | 0 |
uint | 32 位无符号整数类型 | 0 到 4,294,967,295 | 0L |
long | 64 位有符号整数类型 | -923,372,036,854,775,808 到 9,223,372,036,854,775,807 | 0.0 |
ulong | 64 位无符号整数类型 | 0 到 18,446,744,073,709,551,615 | 0.0 |
float | 32 位单精度浮点型 | -3.4 x 1038 到 + 3.4 x 1038 | 0 |
double | 64 位双精度浮点型 | (+/-)5.0 x 10-324 到 (+/-)1.7 x 10308 | 0 |
date | 32位日期型 | 从0000-00-00到9999-12-31 | 0000-00-00 |
time | 32位时间型 | 从00:00:00.000到23:59:59.999 | 00:00:00 |
datetime | 64位日期时间型 | 是date型和time型的合并体 | 0000-00-00 00:00:00 |
4)引用类型
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。换句话说,它们指的是一个内存位置。使用多个变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由一个变量改变的,其他变量会自动反映这种值的变化。内置的 引用类型有:class、array 和 string。
三、变量
1)变量类型
一个变量只不过是一个供程序操作的存储区的名字。在 CRAB 中,每个变量都有一个特定的类型,类型决定了变量的内存大小和布局。范围内的值可以存储在内存中,可以对变量进行一系列操作。
我们已经讨论了各种数据类型。CRAB 中提供的基本的值类型大致可以分为以下几类:
类型 | 举例 |
整数类型 | tiny、byte、short、ushort、int、uint、long、ulong |
浮点型 | float 和 double |
字符类型 | char |
布尔类型 | true 或 false 值 |
日期时间型 | date, time, datetime |
2)变量的定义
变量定义的语法:
<data_type> <variable_list>; |
在这里,data_type 必须是一个有效的 CRAB 数据类型,可以是 char、int、float、double等等数据类型。variable_list 可以由一个或多个用逗号分隔的标识符名称组成。
一些有效的变量定义如下所示:
int i, j, k;char c, ch;
float f, salary; double d; |
您可以在变量定义时进行初始化:
int i = 100; |
四、常量
1)整数常量
整数常量可以是十进制、二进制或十六进制的常量。前缀指定基数:0x 或 0X 或 $ 表示十六进制,0b或0B 表示二进制,没有前缀则表示十进制。
100 // 十进制0x20 // 十六进制
$0c // 十六进制 0b0101 //二进制 |
十进制整数常量也可以有后缀(不分大小写)。
后缀名 | 等值 | 示例 |
K | 1,000 | 1k = 1000 |
M | 1,000,000 | 1m = 1000k |
G | 1,000,000,000 | 1g = 1000m |
T | 1,000,000,000,000 | 1t = 1000g |
W | 10,000 | 1w =10k |
Y | 100,000,000 | 1y = 10000w |
2)浮点常量
一个浮点常量是由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
例如:
3.14159 // 合法314159E-5 // 合法
510E // 非法:不完全指数 210f // 非法:没有小数或指数 .e55 // 非法:缺少整数或小数 |
3)日期时间常量
一个日期常量,前缀是”$”,接着由单引号 ‘ ‘ 或双引号 “”包括,其值由年,月和日组成,中间有分隔符 “-“,或 “/”,一般用 “-“分隔符。
例如:
$”2017-06-16″ //常用格式$”2008/08/08″ //兼容DOS格式 |
一个时间常量,前缀是”$”,接着由单引号 ‘ ‘ 或双引号 “”包括,其值由时,分,秒和毫秒组成,中间有分隔符 “:”和 “.”。秒和毫秒可以缺省不写。
例如:
$”20:08:16″ //常用格式$”20:08:16.250″ //包含毫秒格式
$”20:08″ //仅有时和分,秒缺省为0,毫秒也是为0 |
一个日期时间常量,它是日期常量和时间常量的合并体,中间以空格分隔,可以相互转换。
例如:
$”2017-06-16 20:08:16″ //常用格式$”2017-06-16 20:08:16.250″ //完整格式,包含毫秒格式
$”2017-06-16 20:08″ //仅有日期和时和分,其它缺省为0 |
4)字符与字符串
CRAB语言并不区分字符与字符串,这两者都统一识别为字符串。
字符串常量是括在单引号 ‘ ‘ 或双引号 “” 里,或是在引号外面使用转义符。字符串常量包含的字符,可以是:普通字符、转义序列。
例如:
“Hello World” //常用格式’I am aleyn.wu’ //完整格式,包含毫秒格式
“I’m programer” //当需要某个引号的时候,可以用另外的引号包括 “Want return”\r\n //在引号外连接转义符和转义序列 |
5)特殊常量
以下三个常量,属于系统原生自带的:
类型 | 举例 |
true | 布尔值,字面意思是:真,是 |
false | 布尔值,字面意思是:假,否 |
null | 空值,仅用于引用类型变量,或判断。 |
6)常量的定义
常量是使用 const 关键字来定义的 。定义一个常量的语法如下:
const <constant_name> = value; |
常量的定义不需要指定常量类型,系统会自动识别常量类型。常量定义之后,也不占用内存,而且仅仅在编译期间有效。常量在定义的时候也可以使用常量表达式,也就是所有的未知数都必须是常量。
例如:
const PI = 3.14159;const LED_ON = 1;
const KEY_PRESS = 0x01000000; const KEY_PRESS_F1 = KEY_PRESS + 0x11; |
五、 运算符
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。CRAB 有丰富的内置运算符,分类如下:
1)算术运算符
下表显示了 CRAB 支持的所有算术运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
+ | 把两个操作数相加 | A + B 将得到 30 |
– | 从第一个操作数中减去第二个操作数 | A – B 将得到 -10 |
* | 把两个操作数相乘 | A * B 将得到 200 |
/ | 分子除以分母 | B / A 将得到 2 |
% | 取模运算符,整除后的余数 | B % A 将得到 0 |
++ | 自增运算符,整数值增加 1 | A++ 将得到 11 |
— | 自减运算符,整数值减少 1 | A– 将得到 9 |
# | 字符串连接符,专用于字符串操作 | “A:” # A将得到 “A:10” |
2)关系运算符
下表显示了 C# 支持的所有关系运算符。假设变量 A 的值为 10,变量 B 的值为 20,则:
运算符 | 描述 | 实例 |
== | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 为假。 |
!=<> | 检查两个操作数的值是否相等,如果不相等则条件为真。<> 与 != 相同的功能,主要是兼容其它语言格式 | (A != B) 为真。(A <> B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 为假。 |
< | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
3)逻辑运算符
下表显示了 CRAB 支持的所有逻辑运算符。假设变量 A 为布尔值 true,变量 B 为布尔值 false,则:
运算符 | 描述 | 实例 |
&&and | 称为逻辑与运算符。如果两个操作数都非零,则条件为真。and 和 $$ 是相同的功能,建议用 and 运算符,更直观。 | (A && B) 为false(A and B) 为false |
||or | 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。or 和 || 是相同的功能,建议用 or 运算符,更直观。 | (A || B) 为true(A or B) 为true |
!not | 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。not 和 ! 是相同的功能,建议用 not 运算符,更直观。 | !B 为truenot B 为true |
^^xor | 称为逻辑异或运算符。如果两个操作数中其中一个为真,另一个为假,则条件为真。xor 和 ^^ 是相同的功能,建议用 xor 运算符,更直观。 | (A ^^ B) 为true(A xor B) 为true |
4)位运算符
位运算符作用于位,并逐位执行操作。
下表列出了 CRAB 支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 |
& | 如果同时存在于两个操作数中,二进制 AND 运算符复制一位到结果中。 | (A & B) 将得到 12,即为 0000 1100 |
| | 如果存在于任一操作数中,二进制 OR 运算符复制一位到结果中。 | (A | B) 将得到 61,即为 0011 1101 |
^ | 如果存在于其中一个操作数中但不同时存在于两个操作数中,二进制异或运算符复制一位到结果中。 | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 二进制补码运算符是一元运算符,具有”翻转”位效果,即0变成1,1变成0。 | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< | 二进制左移运算符。左操作数的值向左移动右操作数指定的位数。 | A << 2 将得到 240,即为 1111 0000 |
>> | 二进制右移运算符。左操作数的值向右移动右操作数指定的位数。 | A >> 2 将得到 15,即为 0000 1111 |
5)赋值运算符
下表列出了 CRAB 支持的赋值运算符:
运算符 | 描述 | 实例 |
= | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
+= | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
-= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C – A |
*= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
/= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
%= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
<<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
>>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
&= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
|= | 按位或且赋值运算符 | C |= 2 等同于 C = C | 2 |
#= | 字符串连接且赋值运算符 | C #= A 相当于 C = C # A |
6)其他运算符
下表列出了 C# 支持的其他一些重要的运算符。
运算符 | 描述 | 实例 |
sizeof() | 返回数据类型的大小。 | sizeof(int),将返回 4. |
typeof() | 返回 class 的类型。 | typeof(StreamReader); |
? : | 条件表达式 | 如果条件为true ? 则为 X : 否则为 Y |
Is | 判断对象是否为某一类型。 | If( Ford is Car) // 检查 Ford 是否是 Car 类的一个对象。 |
in | 判断变量是否在一个列表里 | If (I in [1,2,3]) //检查I 是否为1,2,3中任意一个 |
六、条件判断
判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。
1)if语句
一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。语法如下:
if (boolean_expression){
/* 如果布尔表达式为true将执行的语句 */ } |
2)if…else…语句
一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。
if (boolean_expression){
/* 如果布尔表达式为true将执行的语句 */ } else { /* 如果布尔表达式为false将执行的语句 */ } |
3)if语句嵌套
if语句可以嵌套使用,格式如下:
if (boolean_expression1){
} else if (boolean_expression2) { } else if … { } else { } |
3)if (.. in..) 语句
if..in..语句,相当于把几个类似的情况,都集中一起判断,既能方便直观,又能节省代码空间。
此语句仅可单独使用,不可以嵌套使用,也不可以使用else语句。语法如下:
if (var_name in [case list]){
/* 如果布尔表达式为true将执行的语句 */ } |
范例:
if (I in [1, 2, 3..5]){
/* 如果布尔表达式为true将执行的语句 */ } |
以上语句相当以下语句的效果
if ((I == 1) || (I == 2) || ((I>=3) && (I <=5))){
/* 如果布尔表达式为true将执行的语句 */ } |
4)switch语句
一个 switch 语句允许测试一个变量等于多个值时的情况。语法如下:
switch(expression){
//单值的情况 case constant-expression1 : { statement(s); break; //可选项 } //多值的情况 case constant-expression2, constant-expression3 : { statement(s); break; //可选项 } //范围的情况 case constant-expression4..constant-expression6 : { statement(s); break; //可选项 }
/* 您可以有任意数量的 case 语句 */
default : //可选项 { statement(s); break; //可选项 } } |
- switch 语句中的 expression 必须是一个值类型或枚举类型。
- 一个 switch 中可以有任意数量的 case 语句。
- case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是常量类型。
- case 可以是这三种情况:单值, 多值, 范围, 但这三种情况可以任何组合。
- 当被测试的变量等于 case 中的常量时,case 后跟的语句将被执行,直到遇到 break 语句为止,或是遇到下一个case开头为止。
- break不是必须的,当前的case情况结束的时候,将会自动跳转到switch结束位置。
- 如果在case情况里任意位置加入break,则运行到此位置的时候,会立刻跳转到结束位置。
- default是以上case情况都不符合的时候才会运行的。它不是必须的。
- CRAB 不支持从一个 case 标签显式贯穿到另一个 case 标签。
范例:
switch(I){
//单值的情况 case 1 : { statement(s); } //多值的情况 case 2, 3, 4 : { statement(s); } //范围的情况 case 5..8 : { statement(s); } //多种情况混合使用 case 9, 10, 12, 20..30 : { statement(s); } default : { statement(s); } } |
七、循环控制
1)for语句
一个 for 循环是一个允许您编写一个执行特定次数的循环的重复控制结构。语法如下:
for ( init; condition; increment ){
statement(s); } |
下面是 for 循环的控制流:
- init 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。
- 接下来,会判断 condition。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。
- 在执行完 for 循环主体后,控制流会跳回上面的 increment 语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。
- 条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for 循环终止。
范例:
for ( I = 0; I < 10; I++ ){
print(I); } |
2)while语句
只要给定的条件为真,while 循环语句会重复执行一个目标语句。语法如下:
while(condition){
statement(s); } |
condition 必须是布尔表达式。当条件为真时执行循环。当条件为假时,程序流将继续执行紧接着循环的下一条语句。所以在这里,while 循环的关键点是循环可能一次都不会执行。当条件被测试且结果为假时,会跳过循环主体,直接执行紧接着 while 循环的下一条语句。
范例:
I = 0;while(I < 10) //当 I<10时,继续上面的循环
{ statement(s); I++; } |
3)do..while语句
do…while 语句与 while 语句类似,不同的地方在于,while语句是在循环头部测试循环条件,而do…while 语句在循环的尾部检查它的条件。语法如下:
do{
statement(s); } while(condition); |
do…while 语句会确保里面的语块至少会执行一次循环。
范例:
I = 0;do
{ statement(s); I++; } while(I < 10); //当 I<10时,继续上面的循环 |
4)repeat..until语句
repeat..until语句与 do..while 语句类似, 不同的地方在于,do..while语句是在测试循环条件为true时继续循环,而repeat..until 语句在测试循环条件为true时结束循环。语法如下:
repeat{
statement(s); } until(condition); |
同样的,repeat..until 语句也会确保里面的语块至少会执行一次循环。
范例:
repeat{
dosomething(); } until error; //当error为true时,结束循环,否则继续上面的循环。 |
5)循环控制语句
循环控制语句将会更改执行的正常序列。CRAB 提供了break和continue两个控制语句:
break 语句有以下两种用法:
- 当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
- 它可用于终止 switch 语句中的一个 case。
- 如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。
continue 语句
- continue 会跳过当前循环中的代码,强迫开始下一次循环。
- 对于 for 循环,continue 语句会导致执行条件测试和循环增量部分。
- 对于 while和..while和repeat..until 循环,continue 语句会导致程序控制回到条件测试上。
八、函数
1)常规函数
常规函数是指用户自己定义的,把一些相关的语句组织在一起,用来执行一个任务的语句块。
一个常规函数通常包括函数名称,参数,返回值,任务语句块,这四个定义内容。
2)事件函数
事件函数与普通函数很相似,不同的地方在于,一是事件函数不可以有参数,二是事件函数必须有事件标识ID,三是事件函数仅提供给系统调用,用户不能直接调用。详情请参阅事件部分。
3)属性读写函数
属性读写函数是附加在属性上用于对应读和写的特殊函数。属性读写函数的名称是固定的,其中,属性读函数为get,写函数为set。当用户对属性进行读或写的时候,将会触发和调用相对应的读或写函数。详情请参阅属性部分。
4)接口函数
接口函数的定义部分与普通函数差不多,但前面需要加上extern指示符,而且函数头后面不可以有执行的任何语句块。接口函数是用来与宿主程序交互与沟通的特殊函数。详情请参阅接口部分。
5)类成员函数
类成员函数与普通函数一样,都有函数头,参数,任务语句块,等等。不同的地方在于,类成员函数在类结构定义里面,在调用的时候,同样需要与类实例一起配套使用。详情请参阅类部分。
6)内嵌函数
CRAB语言有四个内嵌函数,分别是TypeOf,SizeOf,OpenEvent和CloseEvent函数。
- TypeOf函数用于检测变量类型。
- SizeOf函数用于检测变量大小。
- OpenEvent函数用于打开全局事件驱动。
- CloseEvent函数用于关闭全局事件驱动。
7)特殊函数
CRAB语言有两个特殊函数,分别是main函数与setup函数。
- main函数是应用程序的主入口,它不可缺失。
- main函数没有任何参数,也不能返回任何类型的参数。
- 当main函数结束的时候,或是遇到return语句的时候,应用程序将结束它的生命周期。
- setup函数是应用程序初始化函数,一般是由IDE自动生成,开发者不应自己编辑setup函数。
- setup函数是可选项。如果有setup函数存在,则应用程序会先执行setup函数,然后再执行main函数。
- setup函数和main函数一样,没有任何参数,也不能返回任何类型的参数。
九、常规函数
1)常规函数也是全局函数,只要定义了,后面任何地方都可以调用。语法如下:
<Access Specifier> <Return Type> <Method Name>(Parameter List){
Method Body } |
- Access Specifier:访问修饰符,对于常规函数,此修饰符无效,所以可以忽略不写。
- Return type:返回类型,一个函数可以返回一个值。返回类型是函数返回的值的数据类型。如果函数不返回任何值,则返回类型为 void。
- Method name:函数名称,是一个唯一的标识符,大小写不敏感的。它不能与声明的其他标识符相同。
- Parameter list:参数列表,使用圆括号括起来,该参数是用来传递和接收函数的数据。参数列表是指函数的参数类型、顺序和数量。参数是可选的,也就是说,一个函数可能不包含参数。
- Method body:函数主体,包含了完成任务所需的指令集。
范例:
void MyFunc(int P1, int P2) //这个位置,继续定义,并写函数主体。{
Method Body } |
2)常规函数可以先预定义,然后在后面的任意地方再继续写函数主体。
函数的预定义一般用于函数之间的相互调用,如果没有预定义,那前面定义的函数调用者,将无法找到后面才定义的另一个函数。
范例:
void MyFunc(int P1, int P2); //函数的预定义必须在函数头的位置以;结束
… //这里可以是任意代码
void MyFunc(int P1, int P2) //这个位置,继续定义,并写函数主体。 { Method Body } |
3)参数的定义
常规函数可以有任意个参数,也可以没有参数。
参数的完整定义方式和变量的定义方式差不多,惟一不同的地方就是,参数可以指定为输出方式。
<out> <data_type> <param_name> |
- out是可选项,它指示在函数结束时,需要把该参数的值输出给函数调用者。
- data_type 必须是一个有效的数据类型,可以是 char、int、float、double等等数据类型。
- param_name是一个唯一的标识符,大小写不敏感的。它不能与它的函数名称相同,也不能与其它已声明的参数名称相同。
- 参数与参数之间,需要用逗号来分隔。
范例:
void MyFunc(int P1, int P2, out int P3){
Method Body } |
4)返回类型与返回方式
一个函数可以返回一个值,返回的类型是函数返回的值的数据类型。如果函数不返回任何值,则返回类型为 void。
函数的返回方式,可以使用return 语句,后面带表达式,该表达式的运算结果必须与返回类型相同。
还可以使用result变量,每一个函数,都有一个默认自带的与返回类型相同的变量result,我们叫它返回值变量。在函数的任何地方,都可以使用result变量,而不会产生让函数立刻返回的效果。如果使用result变量,则在需要函数返回的时候,可以直接使用return语句,而不需要带一个表达式。
范例:
int Func1(int P1, int P2){
return P1 + P2; //直接使用return语句返回计算值 } int Func2(int P1, int P2) { result = P1 + P2; //任何时候,都可以使用这个result变量 return ; //效果相当于 return result; }
|
5)函数的调用
函数的调用是对指暂停和保存当前的任务位置,跳转到被调用的函数的位置,当执行完被调用的函数任务后,返回到当前任务的位置继续执行。函数调用的方式如下:
<Object Name Path><Call Method Name>(Parameter List); |
- Object Name Path是可选项,如果被调用的函数是接口函数或类成员函数,则在函数名前面需要加个接口名称或类名称或类实例名称。
- Call Method Name 被调用的函数名称。该名称必须是前面已定义的函数。
- Parameter List 需要传递给被调用的函数的参数列表,如果被调用的函数没有任何参数,则这里也不需要任何参数传入。
- 如果对应的参数有out指示符,则传入的参数也必须加上out指示符,而且该参数必须是变量,不可以是表达式或是属性。
- 如果被调用的函数有返回值,则它可以做为表达式的一份子,但它的返回值必须与表达式的类型相融合或兼容。
- 如果被调用的函数有返回值,但调用者并没有相对应的方式去保存它的返回值,则返回值将会被遗弃。
范例:
MyFunc(1,2); //调用MyFunc
int OutVar; MyFuncWithOut( 1, 2, out OutVar); //调用MyFuncWithOut,有输出参数
var R1; R1 = Func1(1, 2); //调用Func1,并获得函数返回值 R1 = 1 + Func2(3, 4) * 5; //调用Func2,并将返回值当做表达式一部分
Func1(1, 2); //调用Func1,并遗弃它的返回值。
//以下是错误行为。 R1 = MyFunc(1, 2); //MyFunc函数并没有返回值,此调用将会失败。 |
十、数组
1)声明数组
数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合,通常认为数组是一个同一类型变量的集合。
声明数组变量并不是声明 number0、number1、…、number99 一个个单独的变量,而是声明一个就像 numbers 这样的变量,然后使用 numbers[0]、numbers[1]、…、numbers[99] 来表示一个个单独的变量。数组中某个指定的元素是通过索引来访问的。
所有的数组都是由连续的内存位置组成的。最低的地址对应第一个元素,最高的地址对应最后一个元素。
在 CRAB 中声明一个数组,您可以使用下面的语法:
datatype[] arrayName; |
- datatype 用于指定被存储在数组中的元素的类型。
- [ ] 指定数组的大小(或长度)。如果数组有多个维度,则此处可以相应的增加,CRAB语言最多支持3个维度的数组。
- arrayName 指定数组的名称。与变量的定义一样,它是一个唯一的标识符,大小写不敏感的,但不可以与其它已定义的标识符相同名称。
范例:
int[] MyArray; //声明一个1维数组int[][] MyRects; //声明一个2维数组 |
2)初始化数组
声明一个数组不会在内存中初始化数组。当初始化数组变量时,您可以赋值给数组。
数组是一个引用类型,所以您需要使用 new 关键字来创建数组的实例。
范例:
int[] MyArray; //声明一个1维数组MyArray = new int[10]; //初始化数组,并为之申请10个元素
int[] MyArray2 = new int[20]; //声明数组,同时初始化数组。 int[][] MyArray3 = new int[20][30] //声明一个2维数组并初始化。 |
3)数组的访问与赋值
数组赋值需要通过使用索引号(数组下标)赋值给一个单独的数组元素。数组的索引号从0开始,最大值为初始化数组时所申请的元素个数。
范例:
int[] MyArray; //声明一个1维数组MyArray = new int[10]; //初始化数组,并为之申请10个元素
MyArray[0] = 123; //给数组的第一个元素(索引号为0)赋值。
int I; for (I=0; I < 10; I++) { MyArray[I] = I * 100; //利用循环来给数组的每一个元素赋值 } |
数组的访问规则与赋值类似。不仅如此,数组的访问还可以通过foreach语句来逐项访问。
范例:
int[] MyArray; //声明一个1维数组MyArray = new int[10]; //初始化数组,并为之申请10个元素
int Item; foreach (Item in MyArray) { Print(Item); //逐项打印数组的每一个元素赋值
//注意,不可以改变Item的值,因为Item的改变,并不会改变MyArray的内容。 Item = 10; //错误 } |
未初始化的数组,它的内存类型为null
范例:
int[] MyArray; //声明一个1维数组
if (MyArray == null) { Print(“MyArray is null”); } |
4)动态数组
数组也可以采用动态初始化的方式。
范例:
int[][] MyArray; //声明一个2维数组
//初始化数组,其中第2维组申请3个元素组,第1维不固定。 MyArray = new int[3][];
//为第2维的每一个元素组单独申请1维元素,每一组个数各自不同。 MyArray[0] = new int[20]; MyArray[1] = new int[30]; MyArray[2] = new int[40];
//同样采用索引号方式访问,多维数组索引号顺序为,高维数在前,低维数在后。 MyArray[0][1] = 1; MyArray[1][12] = 50; MyArray[2][20] = 100; |
5)多维数组的另一种索引号访问方式
范例:
MyArray[0, 1] = 1; // 相当于MyArray[0][1]MyArray[1, 12] = 50; // 相当于MyArray[1][12]
MyArray[2, 20] = 100; // 相当于MyArray[2][20]
|
6)函数的数组参数
在函数的参数定义里,数组参数仅需要声明数组类型和维数即可。
范例:
void MyArrayFunc(int[] ArrayParam){
int Sum = ArrayParam[0] + ArrayParam[1]; //直接使用数组参数。 Print(“Sum = ” # Sum); } |
十一、字符串
字符串是一个特殊的类,它在变量声明之后,无需申请内存即可直接使用。
字符串的最大长度是255个字符,最小长度是0。
1)字符串变量声明
范例:
string MyStr; //声明一个字符串变量string MyStr2 = “Hello”; //声明一个字符串变量,并赋初值 |
2)字符串赋值
字符串在声明之后,还没赋值之前,他的值类型是null。
可以使用任何明文的方式给字符串赋值,也可以使用字符串表达式,或转义序列。
范例:
string MyStr; //声明一个字符串变量
MyStr = “Hello”; //明文字符串赋值方式。 MyStr = 10 + 20; //将普通的值类型表达式的结果赋值给字符串。 MyStr = ‘GoodBye’\r\n; //在字符串后面加上转义序列。 |
3)字符串的连接
字符串可以通过 # 运算符来连接。任何值类型的变量或表达式,只要通过 # 连接符连接到字符串表达式,那将会自动转化为字符串表达式。
范例:
string MyStr; //声明一个字符串变量。
int R1 = 10 + 20; MyStr = “Result = ” # R1; //通过字符串连接符来连接字符串。
date D1 = $”2017-06-20″ MyStr = “Today is ” # D1 # \r\n; //通过连接符来加入日期和转义序列。 |
3)函数定义里的字符串参数
如果函数参数里有字符串参数,则该参数将接受任何值类型参数和字符串,系统会自己根据类型自动转换。
范例:
void ShowStr(string Text);{
Print(Text); }
string MyStr; //声明一个字符串变量 MyStr = “Hello”; //明文字符串赋值方式。
ShowStr(MyStr); //传入一个正规字符串参数 ShowStr(10+20); //传入一个整型运算表达式 ShowStr(true); //传入一个非字符串值 |
大脚蟹快速开发平台学习教程[二]基础入门篇(564.25 KB)