日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

go語言中值類型和指針類型的深入理解_Golang

作者:陳大俠 ? 更新時間: 2022-05-02 編程語言

golang這個語言用起來和java、 c#之類語言差不多,和c/c++差別比較大,有自動管理內存機制,省心省力。

然而,如果寫golang真的按寫java的習慣去寫,也容易出問題,因為golang中有指針的概念,雖然這個指針是c/c++的自動化版本,但是卻也有指針的特征,如果不熟悉其中原理,寫出來的程序雖然不至于有運行BUG,性能卻不友好。

因此,不能完全以寫java的思路去寫golang,一定要注意其中差別。

我們知道,在java之中,除了基本類型之外,所有的變量類型都是引用類型,你可以隨意的將引用當作參數傳遞,也可以將引用當作返回值返回,都不會有任何問題。

public class Main {
    static class Person{
        private String name;
        private String addr;
        private int age;

        public void addAge() {
            age ++;
        }
    }

    private static Person addAge(Person person) {
        person.addAge();
        return person;//可以這么返回,沒任何問題
    }

    public static void main(String[] args){
        Person person = new Person();
        addAge(person);//可以這么調用,沒任何問題
    }
}

如果你沒寫過c/c++,會覺得這一切顯得這么自然,仿佛這是最常規的操作。然而如果你寫過c/c++,就會發現這么寫并不是常態,而是非常美好的事情,在c/c++里面必須避免這么寫。

class Person
{
private:
	string name;
	string addr;
	int age;

public:
	void addAge()
	{
		this->age++;
	}
};

Person addAge(Person person)
{
	person.addAge();
	return person; //不能直接返回,會拷貝person對象
}

int main()
{
	Person person;
	addAge(person);//不能直接傳遞,會拷貝person對象
}

如上面代碼所示,如果將person對象直接傳遞或者返回,會拷貝對象中的數據,產生額外的開銷,因為這是按值傳遞的模式。在java中也有這種按值傳遞的拷貝,但是只會在基本類型上起作用,而基本類型體積很小,long才8個字節,int 4個字節,對象都是按引用傳遞。

在c++中解決這個問題不止一種手段,但是寫出來的代碼都非常蹩腳難看。在這里我們用指針來解決這個拷貝問題

class Person
{
private:
	string name;
	string addr;
	int age;

public:
	void addAge()
	{
		this->age++;
	}
};

Person* addAge(Person* person)
{
	person->addAge();
	return person; //可以返回,不會拷貝整個對象,只會拷貝指針(8字節)
}

int main()
{
	Person person;
	addAge(&person);//取地址后傳遞, 不會拷貝整個對象,只會拷貝指針(8個字節)
	//或者
	Person* pPerson = new Person;
	addAge(pPerson);//直接傳遞指針
  delete pPerson;//動態分配必須刪除,否則有內存泄露風險
}

c++的做法是不是比java費事的多,所以平時我們吐槽java語法臃腫被c#、person、kotlin調用,而它卻能吊打c++,因為c++能讓你好好的傳遞參數和返回值都做不到。

golang整體的機制雖然偏向于java的易用性,而在變量傳遞返回這一塊,卻繼承了c++的習慣,區分按值傳遞和按指針傳遞,如果寫代碼的時候值和指針不分,雖然程序不會報錯,但是卻會產生額外的拷貝開銷,對性能不友好。

type Person struct {
	name string
	addr string
	age int
}

func (this* Person) addAge()  {
	this.age++
}

func addAge(person Person) Person  {
	person.addAge()
	return person //不能直接返回,會拷貝person對象
}

func main()  {
	person := Person{}
	addAge(person)//不能直接傳遞,會拷貝person對象
}

上面的代碼就是個錯誤示范,在java中這么寫完全沒問題,在golang中卻不行,因為這是按值傳遞,會拷貝對象,就跟c/c++一樣。

type Person struct {
	name string
	addr string
	age int
}

func (this* Person) addAge()  {
	this.age++
}

func addAge(person* Person) *Person  {
	person.addAge()
	return person //可以返回,不會拷貝整個對象,只會拷貝指針(8字節)
}

func main()  {
	person := Person{}
	addAge(&person)//取地址后傳遞, 不會拷貝整個對象,只會拷貝指針(8個字節)
  //或
  person1 := new(Person)
	addAge(person1)//直接傳遞指針, 不會拷貝整個對象,只會拷貝指針(8個字節)
}

這是這是正確的使用方式,按指針傳遞,就跟c/c++一樣。

于此同時,當你直接使用golang內置的map或者切片類型,不用擔心這個問題,因為make出來的map或者切片,默認就是指針類型,傳遞和返回時不會按值拷貝。

func doSome(input map[string]string) map[string]string  {
	input["hello"] = "world"
	return input //可以直接返回,不會按值拷貝,map默認是一個指針
}

func main() {
	data := make(map[string]string,5)
	doSome(data) //可直接傳遞,不會按值拷貝,map是一個指針
}

所以,如果你從java轉到golang,同時又沒有寫過c/c++,那么要萬分注意這個問題,千萬不能完全以寫java代碼的習慣去寫go,否則在循環中出現大對象只拷貝,會是性能毒藥。

總而言之,golang這門計算機語言,同時具有java和c/c++的特征,要能好好使用,需要有這兩門語言的基礎。

總結

原文鏈接:https://zhuanlan.zhihu.com/p/473964302

欄目分類
最近更新