[Go语言] The struct fields can be functions

辨析:

这相当于是虚拟表的手动实现?实现了多态?阅读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

porcupine-Model

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")
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值