Nim教程【十】
openarray类型
注意:openarray类型只能用于参数
固定大小的数组虽然性能不错,但过于呆板,使用取来不是很方便
对于一个方法来说,传入参数如果是一个数组,最好是不要限制数组的长度
也就是说,方法应该能够处理不同大小的数组
openarray类型就是为了满足这样的要求而设计的
openarray类型的变量索引总是从0开始
len、low、high等操作同样试用于openarray类型
原则上,任何一个数组都可以被传递到一个openarray参数中,索引的类型并不重要
但是一定要注意:不能给openarray类型的参数传递多维数组
可变数量的参数
一个可变数量的参数就是一个openarray参数
他可以让开发者传递多个同一类型的参数给一个方法
编译器自动将这些参数转换为一个openarray数组
1 2 3 4 5 6 7 8 | proc myWriteln(f: File , a: varargs[string]) = for s in items(a): write(f, s) write(f, "\n" ) myWriteln(stdout, "abc" , "def" , "xyz" ) # is transformed by the compiler to: myWriteln(stdout, [ "abc" , "def" , "xyz" ]) |
需要注意的是:这种类型的参数必须是方法签名的最后一个参数
另外,你可以通过下面这种方式来动态转换传入的参数的类型
1 2 3 4 5 6 7 8 | proc myWriteln(f: File , a: varargs[string, `$`]) = for s in items(a): write(f, s) write(f, "\n" ) myWriteln(stdout, 123 , "abc" , 4.0 ) # is transformed by the compiler to: myWriteln(stdout, [$ 123 , $ "def" , $ 4.0 ]) |
在这个例子中,$应用于任何参数,
(注意:$应用于字符串时,是一个nop操作)
(译者注:这个语言特性非常像C#里的param关键字)
slice类型
slice类型和subranges类型很相似
但这两个类型的使用场景不尽相同
在实际的业务控制代码中slice类型并不是很常用
但在很多集合类型的操作中,slice起到定义操作数的作用
请看下面的代码:
1 2 3 4 5 6 7 | var a = "Nim is a progamming language" b = "Slices are useless." echo a[ 7. . 12 ] # --> 'a prog' b[ 11. . - 2 ] = "useful" echo b # --> 'Slices are useful.' |
在上面的例子中,slice类型被用于修改一个字符串的一部分
在上面的例子中,-2是一个负数索引(倒数第二个字符)
理论上slice可以容纳任何类型的数据
但是如果slice用于方法的签名中,则必须明确slice容纳的数据类型
Tuple元组类型
Tuple元组类型定义了一系列的有序的属性
可以使用方括号来定义元组,
使用小括号来构造元组,
构造器中属性的顺序必须和元组定义的属性的顺序一致
如果两个元组在定义的时候,使用了相同的属性而且属性的顺序也是一致的
那么这两个元组就是相同的
可以使用t.field来访问一个元组的某个属性
也可以使用t[i]来访问一个元组的第几个属性
来看下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | type Person = tuple [name: string, age: int ] # type representing a person: # a person consists of a name # and an age var person: Person person = (name: "Peter" , age: 30 ) # the same, but less readable: person = ( "Peter" , 30 ) echo(person.name) # "Peter" echo(person.age) # 30 echo(person[ 0 ]) # "Peter" echo(person[ 1 ]) # 30 # You don't need to declare tuples in a separate type section. var building: tuple [street: string, number: int ] building = ( "Rue del Percebe" , 13 ) echo(building.street) # The following line does not compile, they are different tuples! #person = building # --> Error: type mismatch: got (tuple[street: string, number: int]) # but expected 'Person' # The following works because the field names and types are the same. var teacher: tuple [name: string, age: int ] = ( "Mark" , 42 ) person = teacher |
从上面的代码中,大家可以看出
在使用tuple类型的时候,不一定要新创建一个类型出来
上面的代码中的building变量就直接使用了tuple类型,而不像person一样先创建了一个Person类型
只有在元组属性赋值期间元组才可以被拆箱(这里不知道翻译的对不对,原文:Tuples can be unpacked during variable assignment (and only then!).)
os模块的内置splitFile方法,可以返回三个值,一个是路径,一个是文件名,一个是文件扩展名
这个时候就可以应用这个特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import os let path = "usr/local/nimc.html" ( dir , name, ext) = splitFile(path) baddir, badname, badext = splitFile(path) echo dir # outputs `usr/local` echo name # outputs `nimc` echo ext # outputs `.html` # All the following output the same line: # `(dir: usr/local, name: nimc, ext: .html)` echo baddir echo badname echo badext |
上面的代码第一次输出和第二次输出是一样的
只有使用var或者let操作符时,才可以应用元组解包的特性
下面的代码编译不会通过的
1 2 3 4 5 6 7 8 | import os var path = "usr/local/nimc.html" dir , name, ext = "" ( dir , name, ext) = splitFile(path) # --> Error: '(dir, name, ext)' cannot be assigned to |
今天就写到这里吧,喜欢的请帮忙点个推荐
谢谢大家
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
2012-06-16 ASP.NET WebAPI 路由规则与POST数据
2010-06-16 FLASH+ASP.NET(C#)的断点续传(上传)解决方案