範圍 代表兩個值之間的區間。
最常支援範圍的型別是 Int、Char 和 String。
範圍可以用在許多地方,例如快速建立集合、切片字串、檢查某個值是否在範圍內,以及疊代。
範圍是用範圍運算子 .. 或 ... 建立的(分別包含與不包含結尾值)。
1..5 # A range containing 1, 2, 3, 4, 5
1...5 # A range containing 1, 2, 3, 4
會有兩個範圍運算子,是為了建立包含或不包含結尾值的範圍,這在例如處理從零開始的索引時很方便。
範圍也可以用 Range 初始化器建立。
Range.new(1, 5) # A range containing 1, 2, 3, 4, 5
在 Crystal 中使用範圍運算子 .. 或 ... 建立範圍,並且想對該範圍呼叫方法時,需要用括號把範圍包起來。
這是因為不這麼做的話,方法會被當成範圍運算子的第二個引數來呼叫。
(1..5).size # => 5
1..5.size # => Error: undefined method 'size' for Int32
想要切片字串時,可以使用範圍運算子來取得子字串。 也就是建立一個帶有子字串起始與結束索引的範圍。
"Hello World"[0..4] # => "Hello"
"Hello World"[6..10] # => "World"
你也可以用負索引從字串尾端取得子字串。
"Hello World"[-5..-1] # => "World"
"Hello World"[6..-4] # => "Wo"
範圍確實有一組可以用來操作它們的方法。 例如,這些方法可以用來取得範圍中所有值的總和,或檢查範圍是否包含某個值。
| Method | Description | Example |
|---|---|---|
sum |
回傳範圍中所有值的總和 | (1..5).sum # => 15 |
size |
回傳範圍的大小 | (1..5).size # => 5 |
includes? |
如果範圍包含給定的值就回傳 true,否則回傳 false
|
(1..5).includes?(3) # => true |
範圍可以是無盡的,也可以是無始的。
無盡或無始範圍的起始值或結束值為 nil,但定義範圍時可以省略 nil。
當你想例如從字串開頭切片,或一路切到結尾時,使用無始和無盡範圍很方便。
"Hello World"[0..] # => "Hello World"
"Hello World"[4..] # => "o World"
"Hello World"[..5] # => "Hello"
如果沒有用在集合上,又沒有小心使用,無盡範圍可能會產生無盡的序列。
字元可以用在範圍中,讓你取得兩個字元之間的字元區間。 例如,當你想取得字母表時就很方便。
'a'..'z' # A range containing ['a', 'b', 'c', ..., 'z']
字串也可以用在範圍中,讓你取得兩個字串之間的字串區間。
但當字串範圍中使用多個字元時,它的行為和 Char 稍有不同。
在處理更複雜的字串範圍時,它的行為可能會讓人困惑,所以要小心。
("aa".."az") # A range containing ["aa", "ab", "ac", ..., "az"]
身為西洋棋愛好者,你想寫出自己版本的這款遊戲。 沒錯,網路上或許早已有許多現成的西洋棋實作,但你的版本會獨一無二!
你先從實作棋子的基本移動系統開始。
這場西洋棋會在寬八格、長八格的棋盤上進行。 棋盤上的每個格子都用一個字母和一個數字來標示。
遊戲需要儲存棋盤上的行。 行是棋盤上橫向的排列,編號從 1 到 8。
遊戲也需要儲存棋盤上的列。 列是棋盤上縱向的排列,以字母 A 到 H 來標示。
定義 Chess::RANKS 和 Chess::FILES 這兩個常數,分別儲存行與列的範圍。
Chess::RANKS
# => 1..8
Chess::FILES
# => 'A'..'H'
遊戲需要檢查某個格子是否有效。 當格子的行和列都落在行與列的範圍內時,這個格子就是有效的。
定義 Chess.valid_square? 方法,它接受引數 rank(存放該行的整數)和 file(存放該列的字元)。
如果行和列都落在行與列的範圍內,這個方法應該回傳 true,否則回傳 false。
Chess.valid_square?(1, 'A')
# => true
遊戲需要取得玩家的暱稱。 暱稱是玩家名字的前兩個字元,加上姓氏的最後兩個字元。 暱稱應該全部轉成大寫。
定義 Chess.nickname 方法,它接受引數 first_name(存放玩家名字的字串)和 last_name(存放玩家姓氏的字串)。
這個方法應該以全大寫的字串回傳玩家的暱稱。
Chess.nickname("John", "Doe")
# => "JOOE"
遊戲需要為每一步移動建立訊息,說明是哪位玩家移動到哪個格子。 訊息應該使用玩家的暱稱,以及他們移動到的格子。 遊戲也必須判斷這步移動是否有效,檢查這個格子的列和行是否落在列與行的範圍內。
如果移動有效,訊息應該是:"{nickname} moved to {square}"
如果移動無效,訊息應該是:"{nickname} attempted to move to {square}, but that is not a valid square"
定義 Chess.move_message 方法,它接受引數 first_name(存放玩家名字的字串)、last_name(存放玩家姓氏的字串),以及 square(存放玩家移動到的格子的字串)。
這個方法應該以字串回傳這步移動的訊息。
Chess.move_message("John", "Doe", "A1")
# => "JOOE moved to A1"