基本类型

V语言是一门静态类型,编译型语言,以下是内置的基本类型:

布尔类型

bool,布尔类型,值只能是true或false.

  1. module main
  2. fn main() {
  3. x := true
  4. y := false
  5. println(x) // true
  6. println(y) // false
  7. println(sizeof(bool)) // 1
  8. }

布尔类型从定义的C代码看是byte(uint8_t)的类型别名.

true是常量1,false是常量0.

使用sizeof(bool)可以看到bool类型的长度是1个字节.

  1. typedef uint8_t byte;
  2. ...
  3. #ifndef bool
  4. typedef byte bool;
  5. #define true 1
  6. #define false 0
  7. #endif

数值类型

数值类型分为整数和小数.

整数

类型 长度 取值范围 说明
i8 1字节 -128 到 127 有符号8位整数
i16 2字节 -32,768 到 32,767 有符号16位整数
int 4字节 -2,147,483,648 到 2,147,483,647 int总是32位整数,即i32
i64 8字节 -9223372036854775808到9223372036854775807 有符号64位整数
byte 1字节 0 到 255 无符号8位整数,即u8
u16 2字节 0 到 65,535 无符号16位整数
u32 4字节 0 到 4,294,967,295 无符号32位整数
u64 8字节 0 到 18446744073709551615 无符号64位整数

小数

类型 长度 取值范围 说明
f32 4字节 32位小数
f64 8字节 64位小数

数字可以通过前缀标识对应的进制,也可以增加下划线,进行视觉上的分隔,不影响本来的值.

  1. mut c := 0xa_0 //十六进制数字a0
  2. println(c) //输出160
  3. c = 0b10_01 //二进制数字1001
  4. println(c) //输出9
  5. c = 1_000_000 //十进制数字1000000
  6. println(c) //输出1000000

如果不希望由编译器自动类型推断,可以通过T(value)的格式,显式声明变量类型,T是类型,value是变量值.

  1. x:=i64(3) //x是i64类型,而不是默认推断的int
  2. y:=f32(3.0) //y是f32类型,而不是默认推断的f64

字节类型

  1. module main
  2. fn main() {
  3. b := byte(98)
  4. println(b.str()) // 98
  5. println(b.ascii_str()) // b
  6. }

字符串类型

string字符串类型,字符串是一个只读字节数组,默认不可变,UTF-8编码.

单引号和双引号都可以,习惯上都还是使用单引号,V编译器中的代码都是统一使用的单引号.

按作者的说法是可以少按一个shift键,更自然简单一些,不过打破了之前C的使用习惯,让人一开始有些不习惯.

当使用双引号的时候,编译器会自动把双引号自动替换为单引号.

  1. s1:='abc'
  2. s2:="abc"

字符串长度:

  1. s:='abc'
  2. println(s.len) //输出3

字符串连接:

  1. s1:='abc'
  2. s2:='def'
  3. s3:=s1+s2

字符串追加:

  1. mut s:='hello ' //必须是可变才可以追加
  2. s+='world'
  3. println(s) //输出hello world

字符串插值:

  1. name:='Bob'
  2. println('hello $name') //方式1
  3. println('hello ${name}') //方式2,效果一样,更常用于复杂的表达式,把表达式放在{}里面

判断字符串是否包含子字符串:

  1. fn main() {
  2. s:='abcd'
  3. println(s.contains('c')) //true
  4. println(s.contains('bc')) //true
  5. println(s.contains('bb')) //false
  6. }

遍历字符串:

  1. str := 'abcdef'
  2. //遍历value
  3. for s in str {
  4. println(s.str())
  5. }
  6. //遍历index和value
  7. for i, s in str {
  8. println('index:$i,value:$s.str()')
  9. }

字符串切片/区间:

采用的是左闭右开.

  1. s:='hello_world'
  2. println(s[..3]) //输出hel
  3. println(s[2..]) //输出llo_world
  4. println(s[2..5]) //输出llo

字符串从定义的v代码看,也是一个struct.

  1. pub struct string {
  2. pub: //pub表示这两个字符串的属性都是:公共且只读的
  3. str &byte //一个byte类型的指针,指向字符串的首字节地址
  4. len int //字符串的长度
  5. }

字符串单引号和双引号混合使用

主要的逻辑是:

  • 以单引号为主要使用的符号,双引号也可以使用.
  • 如果有字符串嵌套使用,内外必须不能同时是单引号或者同时是双引号,不然无法正确配对.
  • 如果有加上反斜杠进行转义,则都可以.
  1. module main
  2. fn main() {
  3. s0:='name=tom' //ok
  4. s1:="name=tom" //ok
  5. s2:="name='tom'" //ok
  6. s3:='name="tom"' //ok
  7. //s4:='name='tom'' //error
  8. //s5:="name="tom"" //error
  9. s6:='name=\'tom\'' //ok
  10. s7:="name=\'tom\'" //ok
  11. s8:="name=\"tom\"" //ok
  12. s9:='name=\"tom\"' //ok
  13. println(s0)
  14. println(s1)
  15. println(s2)
  16. println(s3)
  17. // println(s4)
  18. // println(s5)
  19. println(s6)
  20. println(s7)
  21. println(s8)
  22. println(s9)
  23. }

rune类型

rune是u32的类型别名,用4个字节来表示一个unicode字符/码点,跟string不是同一个类型.

rune使用反引号来表示.

  1. module main
  2. fn main() {
  3. s1 := 'a' //单引号,string类型
  4. s2 := 'a' //双引号,string类型
  5. s3 := `a` //反引号,rune类型
  6. println(typeof(s1).name)
  7. println(typeof(s2).name)
  8. println(typeof(s3).name)
  9. println(int(s3)) // 97
  10. //
  11. // c2 := `aa` //编译不通过,报错,只能是单字符
  12. c3 := `中`
  13. println(typeof(c3).name) // rune类型
  14. println(sizeof(c3)) // 4个字节,unicode4.0
  15. println(int(c3)) // 20013
  16. println(c3)
  17. }

常用字符串内置函数,可以参考后面的标准库章节,也可以直接参考vlib/builtin/string.v源代码.

指针类型

voidptr指针类型,用来存储变量的内存地址.

指针本身占用的内存大小就是C语言里面的size_t类型.

通常在32位系统上的长度是32位,64位系统上是64位.

  1. module main
  2. fn main() {
  3. //测试机器是64位操作系统
  4. println(sizeof(voidptr)) //输出8个字节
  5. }

变量前加&表示取内存地址,返回指针类型.

指针类型前加*表示取内存地址对应变量的值.

  1. fn main() {
  2. a := 'abc'
  3. println(&a) // 取变量地址,返回地址
  4. b := &a
  5. println(*b) // 取指针对应的值,返回abc
  6. }

正常情况下,由V创建的变量,因为声明和初始化一定是同时进行的,

所以变量一定会有初始值,V指针一定不会有空值,即0值.

内置函数中的isnil(ptr),是用来判断由C代码生成的指针,是否是空指针.

  1. fn main() {
  2. a := 1
  3. println(isnil(&a)) // 返回false,变量只能通过:=来初始化,一定会有初始值
  4. // 但是通过调用C代码返回的指针,有可能是空指针,所以在使用前可以用isnil函数来判断一下
  5. f := C.popen('ls', 'r')
  6. if isnil(&f) {
  7. // ...
  8. println('f is nil')
  9. } else {
  10. println('f is not nil')
  11. }
  12. }

在V语言中,指针只是表示引用,不能进行指针运算.

只有在unsafe代码块中,V编译器不进行任何检查,允许指针像C那样可以进行指针运算,指针偏移,多级指针.

详细内容可以参考:不安全代码.

类型占用内存大小sizeof()

使用内置函数sizeof(T)来返回类型占用内存大小.

  1. println(sizeof(int)) //4
  2. println(sizeof(byte)) //1
  3. println(sizeof(bool)) //1

变量类型typeof().name

使用内置函数typeof(var).name来返回变量的类型.

  1. module main
  2. struct Point {
  3. x int
  4. }
  5. type MyFn = fn (int) int
  6. type MyFn2 = fn ()
  7. fn myfn(i int) int {
  8. return i
  9. }
  10. fn myfn2() {
  11. }
  12. fn main() {
  13. a := 123
  14. s := 'abc'
  15. aint := []int{}
  16. astring := []string{}
  17. astruct_static := [2]Point{}
  18. astruct_dynamic := [Point{}, Point{}]
  19. //使用typeof().name获取变量的类型
  20. println(typeof(a).name) // int
  21. println(typeof(s).name) // string
  22. println(typeof(aint).name) // array_int
  23. println(typeof(astring).name) // array_string
  24. println(typeof(astruct_static).name) // [2]Point
  25. println(typeof(astruct_dynamic).name) // array_Point
  26. //函数类型
  27. println(typeof(myfn).name) // fn (int) int
  28. println(typeof(myfn2).name) // fn ()
  29. }

类型推断及类型转换

  1. module main
  2. fn main() {
  3. i := 8 // 默认类型推断为int
  4. b := byte(8) // 明确指定类型为byte
  5. ii := int(b) // 强制转换为int
  6. f := 3.2 // 默认推断类型为f64
  7. ff := f32(3.2) // 明确指定类型为f32
  8. f3 := f64(f) // 强制转换为f64
  9. s := 'abc' // 默认推断为string
  10. c := `c` // 默认推断为byte,也就是单字符类型
  11. // 布尔类型可以转换为byte/int或其他整数类型
  12. yes := true
  13. no := false
  14. yes_byte := byte(yes) // 输出1
  15. no_byte := byte(no) // 输出0
  16. yes_int := int(yes) // 输出1
  17. no_int := int(no) // 输出0
  18. // 将字节数组转成字符串
  19. mut byte_arr := []byte{} // 字节数组
  20. byte_arr << `a`
  21. byte_arr << `b`
  22. println(byte_arr) // 输出[a,b]
  23. str := byte_arr.str() // 将字节数组转成字符串
  24. println(str) // 输出[a,b]
  25. }