Nim教程【十】

liulun發表於2015-06-16

openarray型別

注意:openarray型別只能用於引數

固定大小的陣列雖然效能不錯,但過於呆板,使用取來不是很方便

對於一個方法來說,傳入引數如果是一個陣列,最好是不要限制陣列的長度

也就是說,方法應該能夠處理不同大小的陣列

openarray型別就是為了滿足這樣的要求而設計的

openarray型別的變數索引總是從0開始

len、low、high等操作同樣試用於openarray型別

原則上,任何一個陣列都可以被傳遞到一個openarray引數中,索引的型別並不重要

但是一定要注意:不能給openarray型別的引數傳遞多維陣列

可變數量的引數

一個可變數量的引數就是一個openarray引數

他可以讓開發者傳遞多個同一型別的引數給一個方法

編譯器自動將這些引數轉換為一個openarray陣列

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"])

需要注意的是:這種型別的引數必須是方法簽名的最後一個引數

另外,你可以通過下面這種方式來動態轉換傳入的引數的型別

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起到定義運算元的作用

請看下面的程式碼:

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]來訪問一個元組的第幾個屬性

來看下面的程式碼:

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方法,可以返回三個值,一個是路徑,一個是檔名,一個是副檔名

這個時候就可以應用這個特性

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操作符時,才可以應用元組解包的特性

下面的程式碼編譯不會通過的

import os

var
  path = "usr/local/nimc.html"
  dir, name, ext = ""

(dir, name, ext) = splitFile(path)
# --> Error: '(dir, name, ext)' cannot be assigned to

 

今天就寫到這裡吧,喜歡的請幫忙點個推薦

謝謝大家

相關文章