数据类型

基本数据类型

基本数据类型 存储值 说明
type.null null 空值,所有变量默认初始值为null
type.boolean true、false 布尔值,表示条件真、假,注意在静态类型中布尔值为32位长度, flase 存为0,而 true 存为非零值,
type.number 数值 数值默认存储为 64位浮点数(即静态类型中的 double 类型),在 API 函数中如果未加类型声明默认转为 32 位 int 类型,aardio 提供 math.size64() 函数用于 创建 64 位无符号整数(类据类型为 cdata,兼容 API 静态类型中的 LONG 类型)。
type.string 字符串 字符串,字符串指向的内存是只读的字节数组,可用下标读取每个字节的 8 位无符号数值(但不可写入), 任何对字符串的修改都会返回新的字符串(而非修改原来的内存)。在调用静态 API 函数时可作为只读的字符串指针参数使用。 aardio 字符串尾部总会保护性地放置2个隐藏的字节'\0\0'(不计入字符串长度,不包含在字符串中), 因此 aardio 字符串可兼容 C 风格字符串。
type.buffer 原生字节数组 原生字节数组( buffer ) 是使用 raw.buffer() 函数分配的可读写、固定长度的内存,可存取各种二进制数据。可用 [] 下标操作符读写内存中原生字节的 8 位无符号数值,可以用 # 操作符取字节数组长度。 不支持连接操作符,但支持 raw.concat,string.concat,string.join 等函数以不同方式拼接。

buffer 在几乎所有字符串函数中都可以作为字符串使用。在结构体中也可作为指针、 BYTE[]数组的值。在原生 API 参数中可作为内存指针、字符串、输出字符串使用。在 COM 函数中可作为安全数组使用。
注意:如果在一个结构体中,将 buffer 赋值为一个结构体的指针字段,并将这个结构体作为输出参数调用 API, 在 API 函数返回以后,只要指针地址没有改变 —— 则这个字段的值仍然是指向原来的 buffer 对象( 如果指针地址被修改,则会变为新的指针值 )。


buffer 在 json 中会转换为 {type="Buffer";data={} } 格式的表对象,
这种表对象可作为 raw.buffer() 函数的唯一参数还原为 buffer 对象

buffer 尾部总会保护性地放置2个隐藏的字节'\0\0'(不计入字符串长度,不包含在字符串中)。 与动态指针不同的是,即使你不指定初始值,aardio 仍然会初始化 buffer 中所有字节的值为0,buffer 的长度是不可变的。 请参考: raw.buffer 函数
type.pointer 指针 内存指针一般用于存储内存地址.但有时候也可能用于存储句柄地址或者无效的内存地址,内存指针给你最大的自由,同时也带来最大的风险,应谨慎使用。
动态指针 动态指针并不是一个新的类型 - 而是与普通内存指针拥有相同的数据类型, raw.realloc()函数可用于分配、释放一个动态指针,也可以使用 raw.realloc() 重新调整动态指针分配的内存大小,动态指针的地址是可变的,调整大小后应废弃旧的指针地址并更新为 raw.realloc() 返回的新指针。

动态指针会在返回给用户的指针地址前面倒退8个字节记录2个32位字段的内存长度、数据长度信息,然后总是向后移动8个字节将可用的指针地址返回给用户, 动态指针尾部总会保护性地放置2个隐藏的字节'\0\0'(不计入内存长度,不包含在存储数据中)。

动态指针可以作为普通内存指针使用,也可以用于支持动态指针的 raw.realloc() raw.concat() raw.sizeof() 等函数, 用 raw.sizeof() 获取动态指针指向内存的大小,用 raw.concat() 函数可以对动态指针的内存追加拼接数据。 要记住这些操作动态指针的函数不要误传不是由 raw.realloc() 分配的非动态指针进去,aardio 不会检查或阻止这种错误操作。

与 buffer 不同的是,如果不指定初始化值,raw.realloc 就不会对分配的内存设定初始化值, 并且 aardio 不负责自动释放动态指针分配的内存,显式的调用 raw.realloc(0,动态指针) 才能释放一个动态指针。
type.table 数组、
哈希表、
静态结构体
请参考《表》
type.function 函数 请参考:定义函数
type.cdata 内核对象 aardio 内核对象,例如 math.size64() 函数创建的长整数对象。

type.fiber 纤程 fiber.create()创建并返回的纤程对象。 纤程类似线程,但不是线程.
纤程有独立的运行堆栈,并且也可以暂停或继续运行,但是纤程并不会创建新的线程,也不能同时运行多个纤程.

请参考《库函数文档》:内核库->纤程库
type.class 请参考:class

null(空值)

null即变量没有存储任何数据,将一个变量赋值为null等于删除这个变量

boolean(逻辑布尔值)

有两个值,true表示真、 false 表示假。通常用在条件表达式中。
通俗一点说,true表示是、符合条件,false表示不是、不符合条件。

在条件表达式(恒等式除外)中, null、数值0这认为是false
其他有效的数据都被认为是true

与C++类似,aardio认为0为false,非零数值为true,在外部api函数中可以保持一致。

在 aardio 中如果一个函数说明应该返回布尔值(true 或 false ),但是实际允许返回任意类型的值 - 不会再额外说明。 任意类型的值可按上述规则自动转换为布尔值使用,不再额外作出说明。 如果一个函数返回值的用途被描述为“是否 ……” 或相同语义的类似说明,即说明该函数应该返回一个布尔值,不再额外作出说明。

number(数值)

aardio中的数值为 64 位双精度浮点数,数值类型可以使用不同的进制来表示,参考:数值与进制
使用0x前缀表示十六进制数,例:num = 0xA1 + 0xFF,而使用2#前缀可以表示2进制数,使用8#前缀可以表示8进制数。也可以用科学计算法表示数值 num = 6e+20

把一个大于10的数写成a * 10n 的形式,其中a称为尾数、n称为指数,是整数数位只有一位的数,这种计数法叫做科学计数法,也叫10的幂计数法。例如 x= -3.5×105 这里最前面有一个负号,3.5是尾数,两个有效数字,后面以10为基数的指数为5。我们可以将它表示为-3.5E5。

数值的字面值允许加入下划线作为数值分隔符,
例如 123_456 等价于 123456, 2#1010_1100 等价于 2#10101100,
数值分隔符不能使用连续多个下划线,并且不能在字符串中使用数值分隔符,例如:
tonumber("123_456") 返回的是123
("123456") + 1 返回的是一个数值 123457
("123_456") + 1 会报错

string(字符串)

请参考《字符串与编码》

table(表)

请参考《表》

function(函数)


函数是一个子程序,可以接收零个或多个参数、返回一个或多个值。使用function关键字定义函数,使用()操作符调用函数。请参考:定义函数

class(类)


使用class关键字定义类。类可以动态创建数据结构相同的table对象。 请参考:class

fiber(纤程)


fiber.create()创建并返回的纤程对象。 纤程类似线程,但不是线程.
纤程有独立的运行堆栈,并且也可以暂停或继续运行,但是纤程并不会创建新的线程,也不能同时运行多个纤程.

请参考《库函数文档》:内核库->纤程库

转换数据类型


aardio提供三个强制转换动态类型的函数

io.open(); //打开控制台窗口,用来支持io.print函数
n = tonumber( "2" );//tonumber函数强制转换一个变量为数字,如果失败返回null空值
str = tostring( 2 );//强制转换一个变量为字符串,如果失败返回null空值
ptr = topointer( 123 ); //强制转换为指针,如果失败返回null空值
io.print( type(n),type(str),type(ptr) );
execute("pause")

另外,使用2个逻辑非操作符可以将任何值转换为布尔值,例如:

var num = 0;

import console
console.log( !!num )
console.pause()

aardio 也允许数据类型自动转换,规则如下:

1、在逻辑运算中,非 0、非 null、非 false 为 true,反之为 false。

2、使用 等式运算符 比较 2 个值时:
a)、任意值与 true,false 比较则先转换为布尔值。
b)、非布尔值与数值比较,则先转换为数值,然后比较数值是否相等。

要注意 ""== 0 或 ' \t\r\n'== 0 会返回 true,空白字符串自动转换为数值时返回0,
null == 0 会返回 false,因为 null 转换为数值还是 null,null 与 0 不是相等的数值。

3、在算术运算、以及 math 库函数无特别说明的数值参数都支持字符串自动转换为数值,转换失败则抛出异常。
其他内核库、标准库函数一般都支持字符串自动转换为数值,有特别说明或对参数类型有特别要求的除外。

字符串在自动转换为数值时,忽略首尾空白字符,空白字符串会转换为 0,而 tonumber 函数会将空白字符串转换为 null。而且 tonumber 函数会调用 _tonumber 元主法,但自动转换忽略 _tonumber 元主法。

示例:

import console; 
console.log( (
"") + ('\r\n\t ') + 0 ); //显示 0
console.log( tonumber("") === null ); //显示 true
console.pause(true);

通常用于检测参数类型的函数会明确区分字符串与数值,例如 math.isInteger() 函数。
检测与区分参数类型的静态 API 函数、COM 函数也会明确区分字符串与数值。

4、在字符串连接操作时,数值会自动转换为字符串。

要特别注意字符串的字面值两侧的 + 会自动转换为 ++。
例如 "1" + 0 会自动转换为 "1" ++ 0 做字符串连接操作,但 ("1") + 0 会执行加法运算。

函数或属性的类型转换:

除非文档有特别说明,函数参数应使用准确的类型。少量函数会支持可兼容的类型转换 —— 如果文档没有特别说明,一般属于一种容错做法,代码中不应当依赖这种转换。过多的类型转换是不必要的 —— 使用准确的类型是更好的选择。

原生静态类型中的类型转换:

请参考:原生静态类型 不声明调用 API

使用type函数可以读取数据类型。

1、函数原型:

dataType[,structType][,metaType] = type( any )

2、函数说明:

type函数返回对象的基本数据类型dataType。
如果对象是一个struct结构体,则返回结构体类型structType。
如果对象在元表中指定了_type字段的值,则返回元类型metaType。

aardio用字符串描述类型,所以返回的类型都是字符串,
如果没有任何参数,type函数无返回值.

3、调用示例:





io.open(); //打开控制台窗口

io.print( type(null) , type.null );//显示null , null
io.print( type("Hello world") , type.string );//显示 string , string
io.print( type(1000) , type.number );//显示 number , number
io.print( type(io.print) , type.function );//function , function
io.print( type( class{} ) , type.class );//显示 class , class
io.print( type(true) , type.boolean );//boolean , boolean
io.print( type( io.stdin ) , type.cdata );//显示 cdata , cdata
io.print( type( {x=0;y=0} ) , type.table );//显示 table , table
io.print( type( topointer( 1 ) ) , type.pointer );//显示 pointer , pointer

使用type.eq比较数据类型

1、函数原型:

eq = type.eq( obj,obj2 )


2、函数说明:

比较参数一、参数二的类型、元类型、struct类型,如果完全相等返回true,否则返回false。 请注意在 aardio 中如果一个函数说明会返回布尔值( true,false) ,如果未加特别说明则允许返回任何可自动转换为布尔值的其他数据类型的值。 例如 type.eq() 可能会返回 null 值以替代 false,aardio 中的函数说明不再重复说明此类自动类型转换规则。

3、调用示例:

import console;
import time.ole

var tmOle = time.ole();
var tm = time();
 
//type.eq 严格比较所有类型(基础类型、元类型、struct类型)
iftype.eq( tmOle,tm ) ){
    console.log(
"tmOle,tm 类型相同")
}
else{
    console.log(
"tmOle,tm 类型不相同")
}

//time.istime 不比较元类型,因此兼容 oletime
console.log( "是 time 对象吗?",time.istime(tmOle) )

console.pause();