变量初始化器
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgInitialization
- 最后更新: 2024-03-07
变量初始化器支持初始化预建类型变量、UDT 对象和数组。
前言:
预建类型变量、用户自定义类型(UDT)对象和数组在创建时默认初始化为零(或 'Boolean' 类型的 'False')或空字符串。
为避免默认变量初始化的开销,可以使用 'Any' 初始化器与 'Dim' 一起告诉编译器只为变量保留内存空间而不初始化它,这样变量将包含垃圾值。在这种情况下,程序员不应对初始值做任何假设。
预建类型变量、UDT 对象和数组可以使用 'Dim ...' 在声明时赋值,使用下面所示的语法。
预建类型变量、UDT 对象和数组的初始化方式与正常赋值相同,使用 '=' 符号。也可以使用 '=>' 符号,例如在声明固定长度字符串时可以避免声明看起来像表达式。
目录
1. 预建类型变量声明的初始化器语法和有效性
主要的预建类型包括:
整数类型
浮点类型
布尔类型
字符串类型
初始化器语法
以下描述 4 种基本语法。
带初始化器的静态分配:
(1) Dim variable_symbol [As PreBuiltType] = expression
或:
(2) Dim Byref ref_variable_symbol [As PreBuiltType] = variable
带初始化器的动态分配:
(3) Dim ptr_variable_symbol As PreBuiltType Ptr = New PreBuiltType( expression )
或:
(4) Dim Byref ref_variable_symbol As PreBuiltType = *New PreBuiltType( expression )
初始化器有效性
expression:
必须产生 'PreBuiltType' 类型或兼容类型的求值值。
variable:
指定了 'As PreBuiltType' 时,为 'PreBuiltType' 变量或兼容变量。
全局符号的声明语法
如果在带初始化器的预建类型变量声明中使用全局符号('Dim Shared'、'Static [Shared]' 或 'Static Var [Shared]' 代替 'Dim'),初始化器参数必须至少能够在程序启动时求值,以便可以放置在 .data 节中:
可变长度字符串的初始化器语法不再有效,因为
'variable_symbol'必须指向堆中的动态内存块。对于其他预建类型变量,如果提供的参数可以在编译时求值,初始化器语法仍然有效。
示例
start GeSHi
Dim d As Double = 1234.56789
Print d
Sleepend GeSHi
注意:
仅在 -lang fb 中,可以使用 'Var' 代替 'Dim'(删除显式类型声明),'Wstring' 类型的初始化器值除外。
2. UDT 对象声明的初始化器语法和有效性
UDT(用户自定义类型)是用户定义的类型结构,是对已有预建类型的补充。
以下所有内容假设下面的任何语句(1 到 7)都有权访问 UDT 中显式定义的任何构造函数(如果存在)。
初始化器语法
以下描述 7 种基本语法。
带初始化器的静态分配:
(1) Dim udt_symbol As UdtName = ( argument_list )
或:
(2) Dim udt_symbol As UdtName = udt_instance
或:
(3) Dim Byref ref_udt_symbol As UdtName = udt_instance
或:
(4) Dim udt_symbol As UdtName = UdtName( argument_list )
或:
(5) Dim udt_symbol As UdtName = Type[<UdtName>]( argument_list )
带初始化器的动态分配:
(6) Dim ptr_udt_symbol As UdtName Ptr = New UdtName( argument_list )
或:
(7) Dim Byref ref_udt_symbol As UdtName = *New UdtName( argument_list )
参数
argument_list:
任何参数类型的列表(以逗号分隔的项)。
如果只有一个参数,'= Type[<UdtName>]( argument )' 初始化器(如果有效)可以缩短为 '= ( argument )' 甚至 '= argument'(转换构造函数的情况)。
udt_instance:
'UdtName' 或兼容类型(派生类型)的实例。
初始化器有效性
初始化器语法第 (1) 行:
仅当不存在构造函数(既非隐式也非显式)时有效。
初始化器语法第 (2 或 3) 行:
始终有效。
拷贝构造(2)和引用声明(3)的情况。
初始化器语法第 (4) 行:
仅当存在与 'argument_list' 匹配的隐式或显式构造函数时有效。
初始化器语法第 (5) 行:
仅当不存在构造函数(既非隐式也非显式),或者存在至少一个与 'argument_list' 匹配的构造函数(隐式或显式)时有效。
初始化器语法第 (6 或 7) 行:
其有效性遵循与上面 初始化器语法第 (5) 行 相同的规则。
但是,决定隐式构造函数是否存在的规则最为复杂,这取决于类型结构:
除默认构造函数和默认拷贝构造函数外,任何其他类型的构造函数仅在显式定义时才存在。
对于隐式默认构造函数和隐式拷贝构造函数,它取决于类型结构,例如它们两者都存在于(主要情况):
具有或继承了具有隐式/显式默认构造函数的成员字段的类型(包括字符串成员),
或具有具有隐式/显式默认构造函数的基类的类型(包括从 Object) 派生的类型),
....,
否则例如,只有具有初始化器本身的变量成员只会导致隐式默认构造函数,但没有隐式拷贝构造函数。
描述
当 UDT 有隐式构造函数(由于字符串成员,或具有初始化器本身的变量成员,或具有构造函数的数据成员,或从 Object 派生的 UDT,或自 fbc 版本 1.20.0 起包含 STRING*N 字段加另一个数据类型字段)或显式构造函数时,简单的初始化器如 '= ( argument_list )'(列表中的第一个初始化器语法 (1))不再有效。
在这种情况下,可以通过使用与列表中最后四种语法(4 到 7)的初始化表达式匹配的构造函数来应用高级初始化。
列表中较简单的初始化器语法(第一个 (1))始终可以被列表中最后四种初始化器语法(4 到 7)之一替换,但反之不行。
列表中的第二种初始化器语法 (2) 是拷贝构造的特殊情况。这种初始化器语法始终有效,无论是通过默认拷贝构造还是通过拷贝构造函数(隐式或显式)。
列表中的第三种初始化器语法 (3) 是引用声明的特殊情况,必须始终有初始化器。如果 'udt_instance' 是引用(或解引用的指针),这种初始化器语法始终有效。
全局符号的声明语法
如果在带初始化器的 UDT 对象声明中使用全局符号('Dim Shared'、'Static [Shared]' 或 'Static Var [Shared]' 代替 'Dim'),初始化器参数必须至少能够在程序启动时求值,以便可以放置在 .data 节中:
列表中的初始化器语法 (6) 和 (7) 不再有效,因为符号必须指向堆中的动态内存块。
如果提供的参数可以在编译时求值,其他初始化器语法仍然有效。如果初始化器必须调用现有构造函数(隐式或显式),则程序启动时调用的构造函数代码会将"初始"值写入 .data 节。
注释示例
start GeSHi
Type UDT1
Dim As Integer I
Dim As Integer J
End Type
Dim As UDT1 u11 = (1, 2) '' default-construction + initialization
'Dim As UDT1 u12 = UDT1(1, 2) '' not valid: no Constructor(As Integer, As Integer)
Dim As UDT1 u13 = Type<UDT1>(1, 2) '' default-construction + initialization
Dim As UDT1 Ptr pu14 = New UDT1(1, 2) '' default-construction + initialization
Delete pu14
Dim ByRef As UDT1 ru15 = *New UDT1(1, 2) '' default-construction + initialization
Delete @ru15
Dim As UDT1 u16 = u13 '' default copy-construction
'Dim As UDT1 u17 = UDT1(u13) '' not valid: no implicit Constructor(As UDT1)
Dim As UDT1 u18 = Type<UDT1>(u13) '' default-construction + initialization
Dim As UDT1 Ptr pu19 = New UDT1(u13) '' default-construction + initialization
Delete pu19
Dim ByRef As UDT1 ru110 = *New UDT1(u13) '' default-construction + initialization
Delete @ru110
Print
Type UDT2
Dim As Integer I = Any
Dim As Integer J
Declare Constructor ()
Declare Constructor (ByVal _I As Integer, ByVal _J As Integer)
End Type
Constructor UDT2 ()
Print "UDT2.Constructor()"
End Constructor
Constructor UDT2 (ByVal _I As Integer, ByVal _J As Integer)
Print "UDT2.Constructor(Byval As Integer, Byval As Integer)"
This.I = _I
This.J = _J
End Constructor
'Dim As UDT2 u21 = (1, 2) '' not valid: exist constructor (due at least to '= Any' initialiser)
Dim As UDT2 u22 = UDT2(1, 2) '' call Constructor(As Integer, As Integer)
Dim As UDT2 u23 = Type<UDT2>(1, 2) '' call Constructor(As Integer, As Integer)
Dim As UDT2 Ptr pu24 = New UDT2(1, 2) '' call Constructor(As Integer, As Integer)
Delete pu24
Dim ByRef As UDT2 ru25 = *New UDT2(1, 2) '' call Constructor(As Integer, As Integer)
Delete @ru25
Dim As UDT2 u26 = u23 '' default copy-construction
'Dim As UDT2 u27 = UDT2(u23) '' not valid: no implicit Constructor(As UDT2)
'Dim As UDT2 u28 = Type<UDT2>(u23) '' not valid: no implicit Constructor(As UDT2)
'Dim As UDT2 Ptr pu29 = New UDT2(u23) '' not valid: no implicit Constructor(As UDT2)
'Dim Byref As UDT2 ru210 = *New UDT2(u23) '' not valid: no implicit Constructor(As UDT2)
Print
Type UDT3
Dim As Integer I
Dim As String S
Declare Constructor ()
Declare Constructor (ByVal _I As Integer, ByRef _S As Const String)
End Type
Constructor UDT3 ()
Print "UDT3.Constructor()"
End Constructor
Constructor UDT3 (ByVal _I As Integer, ByRef _S As Const String)
Print "UDT3.Constructor(Byval As Integer, Byref As Const String)"
This.I = _I
This.S = _S
End Constructor
'Dim As UDT3 u31 = (1, "2") '' not valid: exist constructor (due at least to string member)
Dim As UDT3 u32 = UDT3(1, "2") '' call Constructor(As Integer, As String)
Dim As UDT3 u33 = Type<UDT3>(1, "2") '' call Constructor(As Integer, As String)
Dim As UDT3 Ptr pu34 = New UDT3(1, "2") '' call Constructor(As Integer, As String)
Delete pu34
Dim ByRef As UDT3 ru35 = *New UDT3(1, "2") '' call Constructor(As Integer, As String)
Delete @ru35
Dim As UDT3 u36 = u33 '' default copy-construction
Dim As UDT3 u37 = UDT3(u33) '' call implicit Constructor(As UDT3)
Dim As UDT3 u38 = Type<UDT3>(u33) '' call implicit Constructor(As UDT3)
Dim As UDT3 Ptr pu39 = New UDT3(u33) '' call implicit Constructor(As UDT3)
Delete pu39
Dim ByRef As UDT3 ru310 = *New UDT3(u33) '' call implicit Constructor(As UDT3)
Delete @ru310
Print
Type UDT4 Extends Object
Dim As Integer I
Dim As Integer J
Declare Constructor ()
Declare Constructor (ByVal _I As Integer, ByVal _J As Integer)
End Type
Constructor UDT4 ()
Print "UDT4.Constructor()"
End Constructor
Constructor UDT4 (ByVal _I As Integer, ByVal _J As Integer)
Print "UDT4.Constructor(Byval As Integer, Byval As Integer)"
This.I = _I
This.J = _J
End Constructor
'Dim As UDT4 u41 = (1, 2) '' not valid: exist constructor (due at least to Object as base)
Dim As UDT4 u42 = UDT4(1, 2) '' call Constructor(As Integer, As Integer)
Dim As UDT4 u43 = Type<UDT4>(1, 2) '' call Constructor(As Integer, As Integer)
Dim As UDT4 Ptr pu44 = New UDT4(1, 2) '' call Constructor(As Integer, As Integer)
Delete pu44
Dim ByRef As UDT4 ru45 = *New UDT4(1, 2) '' call Constructor(As Integer, As Integer)
Delete @ru45
Dim As UDT4 u46 = u43 '' default copy-construction
Dim As UDT4 u47 = UDT4(u43) '' call implicit Constructor(As UDT4)
Dim As UDT4 u48 = Type<UDT4>(u43) '' call implicit Constructor(As UDT4)
Dim As UDT4 Ptr pu49 = New UDT4(u43) '' call implicit Constructor(As UDT4)
Delete pu49
Dim ByRef As UDT4 ru410 = *New UDT4(u43) '' call implicit Constructor(As UDT4)
Delete @ru410
Print
' Note for static UDT declaration + initializer:
' When the initializer expression calling the constructor has only one parameter 'x', example:
' 'Dim As UDT u = UDT(x)', in this case, 'UDT(x)' can be shortened into '(x)' or even 'x', like:
' 'Dim As UDT u = (x)' or even 'Dim As UDT u = x', but all these statements call the constructor.
' (a constructor with one parameter is called a conversion-constructor)
' The six below declarations + initialisers all call only the conversion-constructor
Type UDT5
Dim As Integer I
Declare Constructor ()
Declare Constructor (ByVal _I As Integer)
End Type
Constructor UDT5 ()
Print "UDT5.Constructor()"
End Constructor
Constructor UDT5 (ByVal _I As Integer)
Print "UDT5.Constructor(Byval As Integer)"
This.I = _I
End Constructor
Dim As UDT5 u51 = UDT5(1) '' call Constructor(As Integer)
Dim As UDT5 u52 = Type<UDT5>(1) '' call Constructor(As Integer)
Dim As UDT5 u53 = (1) '' call Constructor(As Integer)
Dim As UDT5 u54 = 1 '' call Constructor(As Integer)
Dim As UDT5 Ptr pu55 = New UDT5(1) '' call Constructor(As Integer)
Delete pu55
Dim ByRef As UDT5 ru56 = *New UDT5(1) '' call Constructor(As Integer)
Delete @ru56
Dim As UDT5 u57 = u54 '' default copy-construction
'Dim As UDT5 u58 = UDT5(u54) '' not valid: no implicit Constructor(As UDT5)
'Dim As UDT5 u59 = Type<UDT5>(u54) '' not valid: no implicit Constructor(As UDT5)
'Dim As UDT5 Ptr pu510 = New UDT5(u54) '' not valid: no implicit Constructor(As UDT5)
'Dim Byref As UDT5 ru511 = *New UDT5(u54) '' not valid: no implicit Constructor(As UDT5)
Print
Sleepend GeSHi
注意:
仅在 -lang fb 中,可以使用 'Var' 代替 'Dim'(删除显式类型声明),但初始化器值的类型不能有歧义。
在上面的示例中,只有 'Var u11 = (1, 2)' 不起作用,但 'Var u13 = Type<UDT1>(1, 2)' 可以工作。
3. 数组声明的初始化器语法和有效性
数组可以是任何 DataType。
初始化器语法
以下描述 1 种基本语法。
(目前不支持引用数组)
Dim array_symbol ([lbound To] ubound) [AS DataType] = { expression [, ...] }
参数
'lbound'、'ubound':
常量数值。
'expression(s)':
以逗号分隔的项给出的列表,然后用花括号括起来。
初始化列表从 'lbound' 到 'ubound' 排序。
必须产生 'DataType' 类型或兼容类型的求值值。
初始化器有效性
'lbound' 和 'ubound' 必须是常量数值,因为可变长度(动态)数组声明不支持任何初始化器。
只有固定长度(静态)数组声明支持初始化器。
全局符号的声明语法
如果在带初始化器的数组变量声明中使用全局符号('Dim Shared' 或 'Static [Shared]' 代替 'Dim'),初始化器参数必须至少能够在程序启动时求值,以便可以放置在 .data 节中:
可变长度字符串的固定长度(静态)数组的初始化器语法不再有效,因为符号必须指向堆中的动态内存块。
对于其他预建类型变量的固定长度(静态)数组,如果提供的表达式可以在编译时求值,初始化器语法仍然有效。
示例
start GeSHi
Dim array(0 To 4) As String = {"array(0)", "array(1)", "array(2)", "array(3)", "array(4)"}
For I As Integer = 0 To 4
Print array(I),
Next I
Print
Sleepend GeSHi
注意:
即使在 -lang fb 中,也不能使用 'Var' 代替 'Dim',因为 'Var' 不支持数组声明。
4. 嵌套初始化器语法
这些初始化变量的方法可以相互嵌套以进行复杂赋值。
例如,初始化多维数组:
start GeSHi
Dim array(1 To 3, 1 To 5) As Integer = _
{ _
{11, 12, 13, 14, 15}, _
{21, 22, 23, 24, 25}, _
{31, 32, 33, 34, 35} _
}
For I As Integer = 1 To 3
For J As Integer = 1 To 5
Print array(I, J),
Next J
Print
Next I
Sleepend GeSHi
在这个声明中,最左维度的值以 5 元素数组的形式给出。
嵌套允许初始化任意维度的数组。
UDT 和数组也可以相互嵌套。
例如,以下代码声明并初始化一个 UDT 数组:
start GeSHi
Type mytype
var1 As Double
var2 As Integer
var3 As ZString Ptr
End Type
Dim MyVar(0 To 1) As mytype = _
{ _
(1.1, 1, @"Hello"), _
(2.2, 2, @"GoodBye") _
}
For I As Integer = 0 To 1
Print MyVar(I).var1, MyVar(I).var2, *MyVar(I).var3
Next I
Sleepend GeSHi
注意:
即使在 -lang fb 中,也不能使用 'Var' 代替 'Dim',因为 'Var' 不支持数组声明。
方言差异
- 在 -lang qb 方言中,变量不能初始化。
- 在 -lang fblite 方言中,
'Dim ... = ...'中可以省略显式类型声明,但仅适用于Integer类型(初始化器值必须与Integer类型匹配)。
与 QB 的差异
- 变量初始化器是 FreeBASIC 新增的。
- 替代语法
'Dim [Byref] As DataType symbolname = ...'是 FreeBASIC 新增的。
另请参阅
返回 目录