赋值和初始化、表达式和数组

数组是一组命名的同类型存储单元,这些存储单元在内存中连续分布,每个存储单元都可以通过其索引进行访问。在某种意义上,数组是一个复合变量,特征包括一个公共标识符、存储值类型和编号元素数量。

例如,由 5 个整数组成的数组可以描述如下:

int array[5];

数组大小在名称后的方括号中指定。元素从 0 到 N-1 编号,其中 N 是数组大小。访问元素(即读取值)时使用的语法类似。例如,要将上述数组的第一个元素打印到日志中,我们可以编写以下语句:

Print(array[0]);

请注意,索引 0 对应第一个元素。要打印最后一个元素,语句将替换为:

Print(array[4]);

当然,在打印数组元素之前,需先向数组中写入有效值。要完成这种记录操作,需要使用一种特殊语句,即赋值运算符。该运算符的一个特殊特性是使用了 = 符号,在符号左边指定数组元素(或变量),在其中进行了记录,符号右侧指定要记录的值或“等效表达式”。这里的“等效表达式”隐含了对计算算术、逻辑和其他类型表达式方面的语言能力要求(我们将在第二章学习这些内容)。表达式的语法与我们在学生时代学过的算术和代数中方程式的书写规则非常相似。例如,可以在表达式中使用加 (+)、减 (-)、乘 (*)、除 (/) 运算。

以下是几个关于运算符的示例,用于填写上述数组中某些元素。

array[0] = 10;                       // 10
array[1] = array[0] + 1;             // 11
array[2] = array[0] * array[1] + 1;  // 111

这些语句演示了以不同方法来进行赋值和构造表达式:在第一个字符串中,字面量 10 被写入 array[0] 元素中,而在第二行和第三行中则使用了表达式进行计算,从而获得结果(为便于查看,已在注释中注明)。

当表达式中包含数组元素(一般情况下是变量)时,计算机会在程序执行期间从内存中读取数组元素的值,并对这些值执行上述运算。

务必要区分赋值语句中 = 字符左边和右边的变量及数组元素的用法:左边是已处理数据的“接收者”(始终是单个),而右边是用于计算的初始数据的“源”(一个表达式中可以有多个“源”,就像本例的最后一个字符串,其中元素 array[0]array[1] 的值相乘)。

在我们的示例中,= 字符用于将值赋给预定义数组的元素。但在有些情况下,在定义变量和数组时立即赋予初始值会很方便。这被称为初始化。= 字符也用于初始化。我们结合应用任务的背景来考虑这个语法。

我们用 Greeting 函数内部的问候语选项来描述字符串数组:

string Greeting(int hour)
{
  string messages[3] = {"Good morning""Good afternoon""Good evening"};
  return "Hello, ";
}

在添加的语句中,不仅定义了包含 3 个元素的messages 数组,还定义了初始化方式,即使用所需的初始值进行填充。初始化操作会在变量/数组名称和类型说明上高亮显示 = 字符。对于变量,必须在 = 后面指定一个值,不需要花括号,而对于数组,可以看到,可以写入多个值,用逗号隔开,并用花括号括起来。

请勿将初始化和赋值相混淆。前者是在定义变量/数组时指定的(只进行一次),而后者出现在特定的语句中(同一个变量或数组元素可以反复被赋予不同的值)。数组元素只能单独赋值:MQL5 不支持一次为所有元素赋值(初始化时可以为所有元素赋值)。

在函数内部定义的 messages 数组只能在函数内部使用,比如参数 hour。然后我们将看到如何描述在整个程序代码中可用的变量。

如何将带有小时数的传入值 hour 转换为三个元素之一?

回想一下,根据我们的思路,hour 的值可以从 0 到 23。如果我们将这个值范围除以 8,将得到从 0 到 2 的值。例如,1 除以 8 将得到 0,7 除以 8 将得到 0(整除时,小数部分忽略不计)。然而,8 除以 8 得 1,那么所有从 8 到 15 的数字除以 8 都得 1。数字 16-23 对应除法结果 2。获得的整数 0、1 和 2 将用作索引以读取 messages 数组元素。

在 MQL5 中,/ 运算可用于整数的整除。

用于获得除法结果的表达式与我们刚刚处理 array 时使用的表达式类似,只是必须使用 hour 参数和 / 运算。我们将使用以下语句来演示将 hour 转换为元素索引的可能实现方式:

int index = hour / 8;

这里定义了一个新的整数变量 index,并由以上表达式的值进行初始化。

不过我们可以省略在 index 变量中保存中间值,并立即将这个表达式转移到方括号中(转移到 = 的右边),其中指定了数组元素编号。

在带有 return 运算符的语句中,我们可以提取相关的问候语如下:

string Greeting(int hour)
{
  string messages[3] = {"Good morning""Good afternoon""Good evening"};
  return messages[hour / 8];
}

这个函数已经基本完成。不过在学习几个章节后,我们会做一些修正。至此,我们将项目以另一个名称 GoodTime0.mq5 保存在文件中,并尝试调用我们的函数。因此在 OnStart 中,我们将在 Print 调用内部使用 Greeting 调用。

void OnStart()
{
  Print(Greeting(0), ", "Symbol());
}

我们保留了问候语和金融工具名称之间的分隔逗号(放在“Hello, ”旁边)。现在 Print 函数调用中有三个自变量:第一个和最后一个自变量将分别调用函数 GreetingSymbol 进行动态计算,而逗号将按原样发送打印。

至此,我们将向 Greeting 函数传送常量 0。它的值将进入 hour 参数。编译并启动程序后,我们可以确保它在日志中打印出所需文本。

GoodTime0 (EURUSD,H1)        Good morning, EURUSD

不过在实践中,问候语必须根据用户指定的时间动态地选择。

至此,我们已经进展到需要设计数据输入的阶段。