學習軌道
/
Go
Go
/
練習
/
極速快感
極速快感

極速快感

學習練習

簡介

在 Go 中,struct 是一連串具名的元素,這些元素稱為_欄位_,每個欄位都有名稱和型別。 欄位名稱在 struct 內必須是唯一的。 struct 可以比擬為物件導向程式設計範式中的_類別_。

定義 struct

使用 type 和 struct 關鍵字可以建立新的 struct,並明確地定義每個欄位名稱和型別。 例如,這裡我們定義一個 Shape struct,它包含形狀的名稱和大小:

type Shape struct {
    name string
    size int
}

struct 中的欄位名稱遵循 Go 的慣例:以小寫字母開頭的欄位,只有同一個套件中的程式碼能存取;以大寫字母開頭的欄位,則可以在其他套件中存取。

建立 struct 的實例

定義好 struct 之後,你需要建立新的實例,並以任意順序使用欄位名稱來定義各個欄位:

s := Shape {
    name: "Square",
    size: 25,
}

要讀取或修改實例的欄位,請使用 . 表示法:

// Update the name and the size
s.name = "Circle"
s.size = 35
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 35

沒有指定初始值的欄位,會擁有它們的零值。 例如:

s := Shape{name: "Circle"}
fmt.Printf("name: %s size: %d\n", s.name, s.size)
// Output: name: Circle size: 0

只要依_順序_定義欄位,就可以不使用欄位名稱來建立 struct 的實例:

s := Shape {
	"Oval",
	20,
}

不過,這種語法被視為_脆弱的程式碼_,因為當新增欄位時,特別是新增的欄位型別不同時,它就可能會壞掉。 在下列範例中,我們為 Shape 新增了一個額外的欄位:

type Shape struct {
	name        string
	description string // new field 'description' added
	size        int
}

s := Shape{
    "Circle",
    20,
}
// Since the second field of the struct is now a string and not an int,
// the compiler will throw an error when compiling the program:
// Output: cannot use 20 (type untyped int) as type string in field value
// Output: too few values in Shape{...}

「New」函式

有時候,有幾個能幫助我們建立 struct 實例的函式會很方便。 依照慣例,這些函式通常叫做 New,或名稱以 New 開頭,但因為它們只是一般的函式,你可以任意命名。 它們或許會讓你想起其他語言中的建構子,但在 Go 中,它們就只是一般的函式。

在下列範例中,我們使用其中一個 New 函式來建立 Shape 的新實例,並自動為形狀的 size 設定預設值:

func NewShape(name string) Shape {
	return Shape{
		name: name,
		size: 100, //default-value for size is 100
	}
}

NewShape("Triangle")
// => Shape { name: "Triangle", size: 100 }

使用 New 函式有下列優點:

  • 驗證傳入的值
  • 處理預設值
  • 由於 New 函式通常和它們所初始化的 struct 宣告在同一個套件中,因此它們甚至可以初始化 struct 的私有欄位

說明

在這個練習中,你會負責籌辦各種遙控車之間的比賽。每輛車都有自己的速度和耗電特性。

車子一開始的電池都是滿的(100%)。 每次你用遙控器駕駛車子時,車子會移動相當於自身速度的距離(單位為公尺),剩餘的電池百分比則會依耗電量下降。

如果車子的電池低於耗電百分比,就無法再駕駛這輛車。

每條賽道都有自己的距離。測試車子的方式,是檢查它能不能在電池耗盡前跑完整條賽道。

1. 建立一輛遙控車

定義一個Car結構體,其中包含下列int型別的欄位:

  • battery
  • batteryDrain
  • speed
  • distance

定義一個函式NewCar,讓你能建立遙控車。這個函式接受兩個參數:車子的速度(單位為公尺)和耗電百分比,兩者的型別都是int,並回傳一個Car實例:

speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
// => Car{speed: 5, batteryDrain: 2, battery:100, distance: 0}

2. 建立一條賽道

定義另一個名為Track的結構體型別,其中的distance欄位型別為整數。 定義一個函式NewTrack,讓你能建立賽道。這個函式只有一個參數,就是賽道的距離(單位為公尺),型別為int:

distance := 800
track := NewTrack(distance)
// => Track{distance: 800}

3. 駕駛車子

實作Drive函式,它會根據車子的速度更新已行駛的公尺數,並依耗電量減少電池電量。 如果電池不足以再行駛一次,車子就不會移動:

speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)
car = Drive(car)
// => Car{speed: 5, batteryDrain: 2, battery: 98, distance: 5}

4. 檢查遙控車能否完成比賽

要完成一場比賽,車子必須能行駛完整條賽道的距離,也就是在越過終點線之前,電池不能先耗盡。 實作CanFinish函式,它會接受一個Car實例和一個Track實例作為參數,並在車子能完成比賽時回傳true,否則回傳false。

假設你現在位於比賽的起跑線,正要發動車子的引擎來參加比賽。 請注意,開始比賽時,車子的電池不一定處於滿電狀態:

speed := 5
batteryDrain := 2
car := NewCar(speed, batteryDrain)

distance := 100
track := NewTrack(distance)

CanFinish(car, track)
// => true
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Go Exercism

準備好開始 極速快感 了嗎?

註冊 Exercism,透過 34 個概念165 個練習 和真人引導來學習並精通 Go,全部免費。