Go語言的Interface(介面)是由一組方法簽章(method signatures)組成的型態,其變數可儲存任意實現其方法組(method sets)的型態的值,目的為定義型態的行為。
使用關鍵字interface
宣告介面。例如下面宣告Worker
介面,其有一方法簽章為Eat()
。
type Worker interface { // declare interface Worker
Eat()
}
當一型態(type)的方法(method)實作了介面中定義的方法簽章則該型態即實作了介面,此稱為隱式介面(implicit interfaces),因為非已明確宣告的方式來實作介面。
例如下面Go的Employee
struct的方法Eat()
實現了Worker.Eat()
,也就是說Employee
實作了Worker
介面。
Go
// declare Worker interface
type Worker interface {
Eat()
}
type Employee struct {
Id int
Name string
Age int
}
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks.")
}
相較於Java的介面要用implements
關鍵字明確宣告來實作,所以是顯式介面(explicit interfaces)。下面則是Java的實作方式。
Java
public interface Worker {
void eat();
}
public class Employee implements Worker{
private long id;
private String name;
private int age;
public void eat() {
System.out.println(this.name + " eat snakes.")
}
}
介面變數可儲存其實作型態的值。例如Worker
的變數worker
可以儲存Employee
的值。
package main
import "fmt"
type Worker interface {
Eat()
}
type Employee struct {
Id int
Name string
Age int
}
// define Employee's method that implements Worker interface's method signature Eat()
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks.")
}
func main() {
var worker Worker // define interface Worker's variable 'worker'
employee := Employee{1, "John", 33} // create Employee value and assign to variable 'employee'
worker = employee // interface variable can hold value of it's implementing type
worker.Eat() // John eat snacks
}
若在Worker
新增一個方法簽章Gossip()
,但Employee
只實現了Worker.Eat()
而未實現Gossip()
,則Employee
沒有成功實作Worker
介面,則將變數值分派到worker
時會發生錯誤。換句話說,一個型態必須實現介面的全部方法簽章才算實作了該介面。
package main
import "fmt"
type Worker interface {
Eat()
Gossip(name, message string) string // add new method signature Gossip()
}
type Employee struct {
Id int
Name string
Age int
}
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks")
}
func main() {
var worker Worker
employee := Employee{1, "John", 33}
worker = employee // cannot use employee (type Employee) as type Worker in assignment:
// Employee does not implement Worker (missing Gossip method)
worker.Eat()
}
下面加入Employee.Gossip()
實現Worker.Gossip()
完成實作。
package main
import "fmt"
type Worker interface {
Eat()
Gossip(name, message string) string
}
type Employee struct {
Id int
Name string
Age int
}
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks")
}
// define Employee's method that implements Worker interface's method signature Gossip()
func (e Employee) Gossip(name, message string) string {
return e.Name + " said " + name + " " + message
}
func main() {
var worker Worker
employee := Employee{1, "John", 33}
worker = employee
worker.Eat() // John eat snacks
gossip := worker.Gossip("Mary", "ugly")
fmt.Println(gossip) // John said Mary ugly
}
介面不允許有兩個相同名稱的方法簽章。
type Worker interface {
Eat()
Eat() // duplicate method Eat
Gossip(name, message string) string
}
方法名稱相同的簽章參數不同一樣不允許。
type Worker interface {
Eat()
Eat(food string) // duplicate method Eat
Gossip(name, message string) string
}
方法簽章名稱不允許空白_
命名。
type Worker interface {
Eat()
_() // methods must have a unique non-blank name
Gossip(name, message string) string
}
介面變數若無實作型態則呼叫方法會發生runtime error。
package main
import "fmt"
type Worker interface {
Eat()
}
func main() {
var worker Worker
fmt.Println(worker) // <nil>
worker.Eat() // panic: runtime error: invalid memory address or nil pointer dereference
}
介面可以有多個型態實作。例如下面Employee
及Manager
都實作Worker
。
package main
import "fmt"
type Worker interface {
Eat()
}
type Employee struct {
Id int
Name string
Age int
}
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks")
}
type Manager struct {
Emp Employee
Title string
}
func (e Manager) Eat() {
fmt.Println(e.Title + " " + e.Emp.Name + " eat steaks")
}
func main() {
var worker1 Worker
employee := Employee{1, "John", 33}
worker1 = employee
worker1.Eat() // John eat snacks
var worker2 Worker
manager := Manager{
Employee{2, "Mary", 44},
"CTO",
}
worker2 = manager
worker2.Eat() // CTO Mary eat steaks
}
一個型態可實作多個介面,例如下面Employee
實作了Worker
及Player
介面。
package main
import "fmt"
type Worker interface {
Eat()
}
type Player interface {
Curse()
}
type Employee struct {
Id int
Name string
Age int
}
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks")
}
func (e Employee) Curse() {
fmt.Println(e.Name + " curse partner idiot")
}
func main() {
employee := Employee{1, "John", 33}
var worker Worker
worker = employee
worker.Eat() // John eat snacks
var player Player
player = employee
player.Curse() // John curse partner idiot
}
介面可集合介面,又稱embedded interface。例如下面Slashie
介面集合了Worker
及Player
介面。
package main
import "fmt"
type Worker interface {
Eat()
}
type Player interface {
Curse()
}
// union the method sets of Worker and Player interface
type Slashie interface {
Worker
Player
}
type Employee struct {
Id int
Name string
Age int
}
func (e Employee) Eat() {
fmt.Println(e.Name + " eat snacks")
}
func (e Employee) Curse() {
fmt.Println(e.Name + " curse partner idiot")
}
func main() {
var slashie Slashie
employee := Employee{1, "John", 33}
slashie = employee
slashie.Eat() // John eat snacks
slashie.Curse() // John curse partner idiot
}
沒有留言:
張貼留言