Go語言實現(xiàn)運算符重載的方法詳解
前言
先帶來日常的 GScript 更新:新增了可變參數(shù)的特性,語法如下:
int add(string s, int ...num){
println(s);
int sum = 0;
for(int i=0;i<len(num);i++){
int v = num[i];
sum = sum+v;
}
return sum;
}
int x = add("abc", 1,2,3,4);
println(x);
assertEqual(x, 10);得益于可變參數(shù),所以新增了格式化字符串的內(nèi)置函數(shù):
//formats according to a format specifier and writes to standard output.
printf(string format, any ...a){}
//formats according to a format specifier and returns the resulting string.
string sprintf(string format, any ...a){}下面重點看看 GScript 所支持的運算符重載是如何實現(xiàn)的。
使用
運算符重載其實也是多態(tài)的一種表現(xiàn)形式,我們可以重寫運算符的重載函數(shù),從而改變他們的計算規(guī)則。
println(100+2*2);
以這段代碼的運算符為例,輸出的結果自然是:104.
但如果我們是對兩個對象進行計算呢,舉個例子:
class Person{
int age;
Person(int a){
age = a;
}
}
Person p1 = Person(10);
Person p2 = Person(20);
Person p3 = p1+p2;這樣的寫法在 Java/Go 中都會報編譯錯誤,這是因為他們兩者都不支持運算符重載;
但 Python/C# 是支持的,相比之下我覺得 C# 的實現(xiàn)方式更符合 GScript 語法,所以參考 C# 實現(xiàn)了以下的語法規(guī)則。
Person operator + (Person p1, Person p2){
Person pp = Person(p1.age+p2.age);
return pp;
}
Person p3 = p1+p2;
println("p3.age="+p3.age);
assertEqual(p3.age, 30);有幾個硬性條件:
operator
目前支持的運算符有:+-*/ == != < <= > >=
實現(xiàn)
以前在使用 Python 運算符重載時就有想過它是如何實現(xiàn)的?但沒有深究,這次借著自己實現(xiàn)相關功能從而需要深入理解。
其中重點就為兩步:
- 編譯期間:記錄所有的重載函數(shù)和運算符的關系。
- 運行期:根據(jù)當前的運算找到聲明的函數(shù),直接運行即可。
第一步的重點是掃描所有的重載函數(shù),將重載函數(shù)與運算符存放起來,需要關注的是函數(shù)的返回值與運算符類型。
// OpOverload 重載符
type OpOverload struct {
function *Func
tokenType int
}
// 運算符重載自定義函數(shù)
opOverloads []*symbol.OpOverload在編譯器中使用一個切片存放。
而在運行期中當兩個入?yún)㈩愋拖嗤瑫r,則需要查找重載函數(shù)。

// GetOpFunction 獲取運算符重載函數(shù)
// 通過返回值以及運算符號(+-*/) 匹配重載函數(shù)
func (a *AnnotatedTree) GetOpFunction(returnType symbol.Type, tokenType int) *symbol.Func {
for _, overload := range a.opOverloads {
isType := overload.GetFunc().GetReturnType().IsType(returnType)
if isType && overload.GetTokenType() == tokenType {
return overload.GetFunc()
}
}
return nil
}查找方式就是通過編譯期存放的數(shù)據(jù)進行匹配,拿到重載函數(shù)后自動調(diào)用便實現(xiàn)了重載。
感興趣的朋友可以查看相關代碼:
總結
運算符重載其實并不是一個常用的功能;因為會改變運算符的語義,比如明明是加法卻在重載函數(shù)中寫為減法。
這會使得代碼閱讀起來困難,但在某些情況下我們又非常希望語言本身能支持運算符重載。
比如在 Go 中常用的一個第三方精度庫 decimal.Decimal ,進行運算時只能使用 d1.Add(d2) 這樣的函數(shù),當運算復雜時:
a5 = (a1.Add(a2).Add(a3)).Mul(a4);
a5 = (a1+a2+a3)*a4;
就不如下面這種直觀,所以有利有弊吧,多一個選項總不是壞事。
GScript 源碼: https://github.com/crossoverJie/gscript
到此這篇關于Go語言實現(xiàn)運算符重載的方法詳解的文章就介紹到這了,更多相關Go語言運算符重載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang中基于HTTP協(xié)議的網(wǎng)絡服務
HTTP協(xié)議是基于TCP/IP協(xié)議棧的,并且它也是一個面向普通文本的協(xié)議。這篇文章主要詳細介紹了Golang中基于HTTP協(xié)議的網(wǎng)絡服務,感興趣的小伙伴可以借鑒一下2023-04-04
golang?基于?mysql?簡單實現(xiàn)分布式讀寫鎖
這篇文章主要介紹了golang?基于mysql簡單實現(xiàn)分布式讀寫鎖,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09
Go語言配置數(shù)據(jù)庫連接池的實現(xiàn)
本文內(nèi)容我們將解釋連接池背后是如何工作的,并探索如何配置數(shù)據(jù)庫能改變或優(yōu)化其性能。文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12

