辨析:
这相当于是虚拟表的手动实现?实现了多态?阅读go接口发现可以用interface来实现多态,与在结构体中定义函数类型可以说是异曲同工吧,其实这种写法也不错,开阔了视野。
另外可参考:C语言里的多态的模拟实现
[ include/iobserver.h ]: 檔名開頭的 i 字母表示 interface
typedef struct _IObserved IObserved;
typedef struct _IObserver IObserver;
struct _IObserved { /* 商品 */
void (*registerObserver)(IObserved *, IObserver *);
void (*notifyObservers)(IObserved *);
void (*removeObserver)(IObserved *, IObserver *);
};
struct _IObserver { /* 顾客 */
void (*handle)(IObserver *);
};
[ include/observed.h ]
typedef struct _Observed Observed;
struct _Observed {
IObserver **observers;
size_t count;
size_t size;
union {
IObserved;
IObserved iobserved;
};
};
extern Observed *Observed_construct(void *);
extern void Observed_destruct(Observed *);
[ include/observer.h ]
#include "iobserver.h"
typedef struct _Observer Observer;
struct _Observer {
union {
IObserver;
IObserver iobserver;
};
};
extern Observer *Observer_construct(void *);
extern void Observer_destruct(Observer *);
[ src/main.c ]
const int OBSERVER_SIZE = 10;
int main() {
Observed *observed = new (Observed);
IObserved *iobserved = &observed->iobserved;
Observer *observers[OBSERVER_SIZE];
for (int i = 0; i < OBSERVER_SIZE; ++i) {
observers[i] = new (Observer);
observed->registerObserver(iobserved, &observers[i]->iobserver);
printf("handle: %p\n", &observers[i]->iobserver);
}
printf("\n");
iobserved->notifyObservers(iobserved);
for (int i = 0; i < OBSERVER_SIZE; ++i)
delete(Observer, observers[i]);
delete(Observed, observed);
return 0;
}
案例分析: 通訊系統的可擴充界面
定義一個通用的通訊界面:
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
} tCommClass;
tCommClass commRs232; /* RS-232 communication class */
commRs232.open = &rs232Open;
commRs232.write = &rs232Write;
tCommClass commTcp; /* TCP communication class */
commTcp.open = &tcpOpen;
commTcp.write = &tcpWrite;
對應的通訊實做: [TCP subclass]
static int tcpOpen (tCommClass *tcp, char *fspec) {
printf ("Opening TCP: %s\n", fspec);
return 0;
}
static int tcpInit (tCommClass *tcp) {
tcp->open = &tcpOpen;
return 0;
}
當然你也可以定義 HTTP subclass
static int httpOpen (tCommClass *http, char *fspec) {
printf ("Opening HTTP: %s\n", fspec);
return 0;
}
static int httpInit (tCommClass *http) {
http->open = &httpOpen;
return 0;
}
測試程式:
int main (void) {
int status;
tCommClass commTcp, commHttp;
// Same ’base’ class but initialized to
// different sub-classes.
tcpInit (&commTcp);
httpInit (&commHttp);
// Called in exactly the same manner.
status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
status = (commHttp.open)(&commHttp, "[](http://www.microsoft.com)http://www.microsoft.com");
return 0;
}
案例分析: Stack ADT
[ source ]
namespace:
stack_push(thing *); /* C */
stack::push(thing *); // C++
用 C++ 表示:
class stack {
public:
stack();
void push(thing *);
thing *pop();
static int an_example_entry;
private:
...
};
「慣 C」表示:
struct stack {
struct stack_type *self;
/* Put the stuff that you put after private: here */
};
struct stack_type {
void (*construct)(struct stack *self); /**< initialize memory */
struct stack *(*operator_new)(); /**< allocate a new struct to construct */
void (*push)(struct stack *self, thing *t);
thing * (*pop)(struct stack *self);
int as_an_example_entry;
} Stack = {
.construct = stack_construct,
.operator_new = stack_operator_new,
.push = stack_push,
.pop = stack_pop
};
使用方式:
struct stack *st = Stack.operator_new(); /* a new stack */
if (!st) {
/* Do something about error handling */
} else {
stack_push(st, thing0); /* non-virtual call */
Stack.push(st, thing1); // cast *st to a Stack and push
st->my_type.push(st, thing2); /* a virtual call */
}
A structure or struct in Golang is a user-defined type, which allows us to create a group of elements of different types into a single unit. Any real-world entity which has some set of properties or fields can be represented as a struct. As we know that in Go language function is also a user-defined type so, you are allowed to create a function field in the Go structure. You can also create a function field in the Go structure using an anonymous function
as shown in Example 2.
Syntax:
type function_name func()
type strcut_name struct{
var_name function_name
}
Let us discuss this concept with the help of the examples:
例1:Go program to illustrate the function as a field in Go structure
package main
import "fmt"
// Finalsalary of function type
type Finalsalary func(int, int) int
// Creating structure
type Author struct {
name string
language string
Marticles int
Pay int
// Function as a field
salary Finalsalary
}
// Main method
func main() {
// Initializing the fields
// of the structure
result := Author{
name: "Sonia",
language: "Java",
Marticles: 120,
Pay: 500,
salary: func(Ma int, pay int) int {
return Ma * pay
},
}
// Display values
fmt.Println("Author's Name: ", result.name)
fmt.Println("Language: ", result.language)
fmt.Println("Total number of articles published in May: ", result.Marticles)
fmt.Println("Per article pay: ", result.Pay)
fmt.Println("Total salary: ", result.salary(result.Marticles, result.Pay))
}
输出:
Author's Name: Sonia
Language: Java
Total number of articles published in May: 120
Per article pay: 500
Total salary: 60000
例2:Go program to illustrate the function as a field in Go structure using anonymous function
package main
import "fmt"
// Creating structure
type Author struct {
name string
language string
Tarticles int
Particles int
Pending func(int, int) int
}
// Main method
func main() {
// Initializing the fields
// of the structure
result := Author{
name: "Sonia",
language: "Java",
Tarticles: 340,
Particles: 259,
Pending: func(Ta int, Pa int) int {
return Ta - Pa
},
}
// Display values
fmt.Println("Author's Name: ", result.name)
fmt.Println("Language: ", result.language)
fmt.Println("Total number of articles: ", result.Tarticles)
fmt.Println("Total number of published articles: ",
result.Particles)
fmt.Println("Pending articles: ",
result.Pending(result.Tarticles, result.Particles))
}
输出:
Author's Name: Sonia
Language: Java
Total number of articles: 340
Total number of published articles: 259
Pending articles: 81
type Model struct {
// Partition functions, such that a history is linearizable if and only
// if each partition is linearizable. If you don't want to implement
// this, you can always use the `NoPartition` functions implemented
// below.
Partition func(history []Operation) [][]Operation
PartitionEvent func(history []Event) [][]Event
// Initial state of the system.
Init func() interface{}
// Step function for the system. Returns whether or not the system
// could take this step with the given inputs and outputs and also
// returns the new state. This should not mutate the existing state.
Step func(state interface{}, input interface{}, output interface{}) (bool, interface{})
// Equality on states. If you are using a simple data type for states,
// you can use the `ShallowEqual` function implemented below.
Equal func(state1, state2 interface{}) bool
// For visualization, describe an operation as a string.
// For example, "Get('x') -> 'y'".
DescribeOperation func(input interface{}, output interface{}) string
// For visualization purposes, describe a state as a string.
// For example, "{'x' -> 'y', 'z' -> 'w'}"
DescribeState func(state interface{}) string
}
使用方法:
setModel := Model{
Init: func() interface{} { return []int{} },
Step: func(state interface{}, input interface{}, output interface{}) (bool, interface{}) {
st := state.([]int)
inp := input.(setInput)
out := output.(setOutput)
if inp.op == true {
// always returns true for write
index := sort.SearchInts(st, inp.value)
if index >= len(st) || st[index] != inp.value {
// value not in the set
st = append(st, inp.value)
sort.Ints(st)
}
return true, st
}
sort.Ints(out.values)
return out.unknown || reflect.DeepEqual(st, out.values), out.values
},
Equal: func(state1, state2 interface{}) bool {
return reflect.DeepEqual(state1, state2)
},
}
func checkEvents(model Model,
history []Event,
verbose bool,
timeout time.Duration) (CheckResult, linearizationInfo) {
model = fillDefault(model)
partitions := model.PartitionEvent(history)
l := make([][]entry, len(partitions))
for i, subhistory := range partitions {
l[i] = convertEntries(renumber(subhistory))
}
return checkParallel(model, l, verbose, timeout)
}
func CheckEvents(model Model, history []Event) bool {
res, _ := checkEvents(model, history, false, 0)
return res == Ok
}
res := CheckEvents(setModel, events)
if res != true {
t.Fatal("expected operations to be linearizable")
}