结构体定义

结构体由变量组成,变量可以是内置类型,也可以是由用户定义的其他类型。结构体用于将逻辑上相关的数据组合在一个容器中。假设我们有一个执行特定计算的函数,并接受一组参数:显示报价历史以供分析的条数、分析开始日期、价格类型和分配的信号数(例如谐波)。

double calculate(datetime startint barNumber,
                 ENUM_APPLIED_PRICE priceint components);

在现实情况中,可能会有更多参数,将它们以列表形式传递给函数并非易事。此外,根据多次计算的结果,将一些最佳设置保存在某种数组中也很有意义。因此,将一组参数表示为一个对象会很方便。

以下是对带有相同变量的结构体的说明:

struct Settings
{
   datetime start;
   int barNumber;
   ENUM_APPLIED_PRICE price;
   int components;
};

说明以 struct 关键字开头,后面是我们选择的标识符。随后是括在花括号中的代码块,代码块内是对结构体中所含变量的说明。此外,这些变量被称为字段或结构体的成员。花括号后有一个分号,因为整个符号是一个定义新类型的语句,而语句后必须有 ';'。

定义了类型后,我们就可以像应用内置类型一样应用自己定义的类型。具体而言,新类型可以让您以常规方式描述程序中的 Settings 变量。

Settings s;

值得注意的是,通过单个结构体描述,您可以创建任意数量的结构体变量,甚至是该类型的数组。每个结构体实例都有自己的一组元素,并且包含独立的值。

要访问结构体的成员,需要提供一个特殊的取消引用运算符,即点字符 '.'。它的左边应该是一个结构体类型的变量,右边则是其中一个可用字段的标识符。下面是为结构体元素赋值的方法:

void OnStart()
{
   Settings s;
   s.start = D'2021.01.01';
   s.barNumber = 1000;
   s.price = PRICE_CLOSE;
   s.components = 8;
}

还可以通过一种更便捷的方法来填充结构体,即聚合初始化。在本例中,'=' 符号写在结构体变量的右边,后面是所有字段的初始值列表,以英文逗号分隔并都括在花括号中。

   Settings s = {D'2021.01.01', 1000PRICE_CLOSE8};

值的类型必须与相应的元素类型相匹配。允许指定的值数量少于字段数量,在这种情况下,剩余字段的值为零。

请注意,只有在变量被初始化时,即在定义变量时,这种方法才会起作用。无法用这种方法赋值一个已经存在的结构体的内容,否则会产生编译错误。

   Settings s;
   // error: '{' - parameter conversion not allowed
   s = {D'2021.01.01', 1000PRICE_CLOSE8};

使用取消引用运算符,还可以读取结构体元素的值。例如,我们使用条数来计算交易品种数量。

   s.components = (int)(MathSqrt(s.barNumber) + 1);

这里的 MathSqrt 是内置的 平方根 函数。

我们引入了一种新类型 Settings,以便更轻松地将一组参数传递给函数。现在,它可以用作更新后的 calculate 函数的唯一参数:

double calculate(Settings &settings);

请注意参数名称前面的 '&',这表示 按引用传递。结构体在作为参数传递时,只能按引用传递。

如果需要从函数返回一组值而不是单个值,也可以使用结构体。假设 calculate 函数不应返回 double 类型的值,而是几个系数和一些交易建议(交易方向和成功概率)。然后,我们就可以定义 Result 结构体的类型,并在函数原型 (Structs.mq5) 中使用。

struct Result
{
   double probability;
   double coef[3];
   int direction;
   string status;
};
 
Result calculate(Settings &settings)
{
   if(settings.barNumber > 1000// edit fields
   {
      settings.components = (int)(MathSqrt(settings.barNumber) + 1);
   }
   // ...
   // emulate getting the result
   Result r = {};
   r.direction = +1;
   for(int i = 0i < 3i++) r.coef[i] = i + 1;
   return r;
}

Result r = {} 行中的空花括号代表最小聚合初始化器:它将结构体的所有字段都填为 0。

如有必要,可以分开进行结构体类型的定义和声明(通常,声明包含在头文件 mqh 中,而定义则包含在 mq5 文件中)。这种扩展语法将在 关于“类”的章节中介绍。