Gox语言中的基本数据类型及其转换(Anko引擎)-GX5.2

* 注:由于0.988版本后,为了减少不必要的文件体积,Gox已经放弃了其他脚本引擎,仅支持Qlang引擎,因此本文中的内容已经无效,仅留作对旧版本的参考。

Gox语言以脚本语言Anko为语法基础,而Anko语言又是基于Go语言(Golang)做了一定的改进,因此数据类型大致类似于Go语言,数据的赋值等操作也类似但略有不同。下面做一些说明,并用实例来进行验证。

变量的声明与赋值

Gox语言中,变量声明可以使用“var”关键字,也可以不用,与JavaScript语言类似,var关键字只是用来指定该变量是局部变量。另外变量无需指定类型,并且同一变量可以改变数据类型,也就是说变量可以随着它其中存放的数值类型而改变自己的类型。看看下面这段代码:

var a = 1

printfln("[%T] %v", a, a)

b = 1

printfln("[%T] %v", b, b)

a = "abc"

printfln("[%T] %v", a, a)

其中,printfln是Gox语言内置的函数,相当于printf函数并且会在最后多输出一个回车换行符。而“%T”和“%v”是从Go语言中继承过来的格式符,“%T”表示输出后面对应变量的类型,“%v”则是输出任意变量的字符串表示。而这段代码中,先对变量a用var关键字定义并赋值,然后又不用var而直接用等号“=”赋值一个新的变量b,最后又给变量a赋一个字符串类型的值。运行后将得到下面的结果:

可以看出,使用关键字var与否在这段代码中对于定义变量并没有什么实质影响,因为都是在一个层级的代码段内。变量a、b都是int64类型,数值都是1,而变量a后来可以被直接赋值为string类型的变量,也就是字符串类型的变量,值为“abc”。这说明Gox语言中变量的类型是可以改变的,这是与Go语言显著的不同之一。

而这段代码,

a = 1
func() {
    a = 2
}()
println(a)

var a = 1
func() {
    a = 2
}()
println(a)

a = 1
func() {
    var a = 2
}()
println(a)

var a = 1
func() {
    var a = 2
}()
println(a)

执行结果是:

可以清楚地看出使用var关键字定义局部变量的效果,前两个函数中没有使用var关键字,导致对变量a的修改其实是修改了全局变量a,而后面两个函数都是用var创建了局部a,它的值的改变不会影响同名的全局变量a,这时候局部变量a与全局变量a其实是两个完全没有关系的变量。

其中的println函数也是Gox语言内置的,与其他语言的println基本相同。

* 另外注意,Gox语言也是大小写敏感的,各种标识符(包括变量名、函数名、结构体名等)大小写不同的话,都会被认为是不同的。

布尔类型

布尔类型英语中一般称作boolean,也常简称bool,布尔类型数据的取值只有true和false两个值,分别代表真与假、是或否等对立的概念。布尔类型的数值或变量经常被用于条件判断分支代码中。

b = true

printf("[%T] %v\n", b, b)

c = false

printf("[%T] %v\n", c, c)

printf("!b = %v\n", !b)

printf("b == c: %v\n", b == c)

printf("1 > 14: %v\n", 1 > 14)

printf("b == true: %v\n", b == true)

printf("b && c: %v\n", b && c)

printf("b || c: %v\n", b || c)

上面这段代码中,printf函数也是Gox语言的内置函数,与其他语言的printf功能是基本一致,与Go语言中的printf函数完全一样。因此,其中如果要输出回车换行符也要用转义字符“\n”。

这段代码执行后,输出结果如下:

其中,可以看出,变量a的值是true,变量b的值是false,“!”是取反(也叫“非”)操作符,如果是false取反则是true,true的取反为false。很多表达式的计算结果也是bool类型的,例如“b==c”表示判断变量b与c中的值是否相等(“==”符号表示判断其两边的变量值是否相等),其结果也是一个bool类型的值,由于b和c中的值并不相等,所以“b == c”的计算结果是false。因此,b == true这个表达式的结果就是true了,因为b的值就是true。“&&”和“||”表示“逻辑与”和“逻辑或”,这与很多其他语言也是一致的,true && true 还是 true,true && false 是 false,false && true 还是 false,false && false 也是 false;而true || true 是 true,true || false 还是 false,false || true 也是 true,false || false 则是 false。

整数类型

c1 = 19

c2 = 18

println(c1 + c2/3)

printfln("%T", c1)

printfln("%T", c1+c2)
printfln("%T", c2/3)
printfln("%T", c1+c2/3)
printfln("%T, %v", (c1+c2/3)*6, (c1+c2/3)*6)

c1++
c1 *= 3

c2 += 5
c2--

printfln("c1: %v, c2: %v, %T", c1, c2, c1)

这段代码的执行结果是:

可以清晰地看出,在做了除法操作后,即使是整数相除,也会变成浮点数类型。并且整数都是64位的。另外,运算符++、--、*=,+=也都有效(还有-=,/=也都可以使用)。

浮点数类型

f1 = 1.32

previus_f1 = f1

f1 = f1 * 0.8

print(previus_f1, "*", 0.8, "=", f1)
println()

f2 = 0.99
f2 /= 0.3

print(0.99, "/", 0.3, "=", f2, "\n")

执行结果为:

需要注意的是,print也是Gox语言的内置函数,功能与其他语言中的print类似,如果要输出回车换行符,可以用本代码中所示的两种方法,一种是加一个没有参数的println函数,另一种是多输出一个转义符“\n”。

字符串类型

下面是一些字符串赋值与操作的例子:

s1 = "abc"

s2 = s1 * 3

pv("s2")

println(s1, "*", 3, "=", s2)

s3 = s2 / 3
printfln("s3: %v", s3)

s4 = "0.99"
s4 += 0.3

printfln("s4: %v", s4)

s5 = "上善若水"

pv("s5")

s6 = toByteSlice(s5)

println(s6)

s7 = toRuneSlice("上善若水")

pv("s7")

pl("s5[1:2] = %#v", s5[1:2])

pl("s6[1:2] = %#v", s6[1:2])

pl("s7[1:2] = %#v", s7[1:2])

pl("toString(s7[1:3]) = %#v", toString(s7[1:3]))

pl("toString(toByteSlice(s7[1:3])) = %#v", toString(toByteSlice(s7[1:3])))

pl("toStringFromRuneSlice(s7[1:3]) = %#v", toStringFromRuneSlice(s7[1:3]))

pl("%c", s7[1])

for i = 0; i < len(s5); i++ {
    pl("%v: %v", i, s5[i])
}

for v in s7 {
    pl("%#T, %v", toChar(v), toChar(v))
}

运行结果是:

这里需要注意的是:

  • pv函数可以查看变量的名称、类型和值,在调试代码的时候比较方便,但注意函数的参数要求传入变量名称,是个字符串;
  • pl函数与printfln作用相同,只是个简写;
  • 字符串做乘法的意义是会重复生成相同的字符串再合并起来;
  • 字符串加法的意义则是两个字符串连接(或者叫合并)起来;
  • 与Go语言相同,对于UTF-8编码的字符,转成[]rune类型才可以处理正确,因此,要想正确地遍历utf-8字符串,需要转换成[]rune类型(rune类型本质上是int32类型),可以用toRuneSlice内置函数来进行;
  • 另外,注意把Rune切片转换回字符串时,不能直接用toString函数,而必须要先转换回ByteSlice(字节切片),用toByteSlice函数,这是一个坑;也可以用toStringFromRuneSlice函数,一步就可以了;
  • toChar函数可以把一个rune类型的数据转换为对应字符的字符串表达形式;

空类型nil

Gox语言中的空类型实际上用到的场景没有那么多,主要用途有以下几种情况:

  • 用于事先声明一个变量,声明的时候可能无法确定类型或取值;例如定义一个在后面赋值的全局变量时;
  • 用于调用Go语言库中会返回nil类型的函数时进行交互和判断,例如常见的error类型;

参看下面的例子:

pv("a")

println(defined("a"))

a = 18

pv("a")

println(defined("a"))

b = nil

pv("b")

println(defined("b"))

tk = import("tk")

c, errT = tk.StrToInt("12ab")

if errT != nil {
    println("Error:", errT.Error())
}

pv("c")

pv("errT")

c, errT = tk.StrToInt("123")

pv("c")

pv("errT")

if errT != nil {
    println("Error:", errT.Error())
}


执行结果为:

代码中的tk.StrToInt函数就是会返回error类型值得函数,当传入参数的字符串无法被转换为整数类型时,返回的第二个值(error类型)将不是nil,而可以正常转换时,将返回nil值。

数据类型的转换

Gox语言中有不少“to”开头的函数用于进行数据转换,参看下面的例子:

a = 1
b = 2

println("type of a is:", typeof(a))

println("a + b =", a+b)
printfln("a + b = %#v", a+b)

a1 = toString(a)
b1 = toString(b)

printfln("type of a1 is: %T", a1)
printfln("value of a1 is: %v", a1)
printfln("internal value of a1 is: %#v", a1)

println("a1 + b1 =", a1+b1)
printfln("a1 + b1 = %#v", a1+b1)

a2 = toFloat(a1)
b2 = toFloat(b1)

printfln("a2 + b2 = %#v", a2+b2)
printfln("type of a2 + b2 is: %T", a2+b2)

运行结果如下:

λ gox scripts\dataTypeConversion.gox
type of a is: int64
a + b = 3
a + b = 3
type of a1 is: string
value of a1 is: 1
internal value of a1 is: "1"
a1 + b1 = 12
a1 + b1 = "12"
a2 + b2 = 3
type of a2 + b2 is: float64

这些“to”开头的转换函数包括:

toString/toStringSlice, toBool(and tryToBool which returns the result like (bool, error))/toBoolSlice, toFloat64/tryToFloat64/toFloat/toFloatSlice, toInt64/tryToInt64, toInt/tryToInt/toIntSlice, toRune/toRuneSlice, toByteSlice, toChar, toDuration

其中,toChar转换出来的还是string类型,toDuration转换出来的对应于Go语言的time.Duration类型。几个“tryTo”开始的函数会尝试进行转换,如果不成功,会在第二个error类型的参数中返回错误信息。

另外,从这里也可以看出Gox语言支持的一些本文没提到的基础类型,如rune、int64、float64等,但都大同小异,可以视情况选用。

推荐阅读更多精彩内容