go 學習筆記之僅僅需要一個示例就能講清楚什麼閉包

2021-01-10 雪之夢技術驛站

本篇文章是 Go 語言學習筆記之函數式編程系列文章的第二篇,上一篇介紹了函數基礎,這一篇文章重點介紹函數的重要應用之一: 閉包

空談誤國,實幹興邦,以具體代碼示例為基礎講解什麼是閉包以及為什麼需要閉包等問題,下面我們沿用上篇文章的示例代碼開始本文的學習吧!

斐波那契數列是形如 1 1 2 3 5 8 13 21 34 55 的遞增數列,即從第三個數開始,後一個數字是前兩個數字之和,保持此規律無限遞增...

開門見山,直接給出斐波那契數列生成器,接下來的文章慢慢深挖背後隱藏的奧秘,一個例子講清楚什麼是閉包.

「雪之夢技術驛站」: 如果還不了解 Go 語言的函數用法,可以參考上一篇文章: go 學習筆記之學習函數式編程前不要忘了函數基礎

Go 版本的斐波那契數列生成器

「雪之夢技術驛站」: Go 語言支持連續賦值,更加貼合思考方式,而其餘主流的程式語言可能不支持這種方式,大多採用臨時變量暫存的方式.

Go 版本的單元測試用例

「雪之夢技術驛站」: 循環調用 10 次斐波那契數列生成器,因此生成前十位數列: 1 1 2 3 5 8 13 21 34 55

背後有故事

小小的斐波那契數列生成器背後蘊藏著豐富的 Go 語言特性,該示例也是官方示例之一.

支持連續賦值,無需中間變量「雪之夢技術驛站」: Go 語言和其他主流的程式語言不同,它們大多數最多支持多變量的連續聲明而不支持連續賦值.

這也是 Go 語言特有的交換變量方式,a, b = b, a 語義簡單明確並不用引入額外的臨時變量.

「雪之夢技術驛站」: Go 語言實現變量交互的示例,a, b = b, a 表示變量直接交換.

而其他主流的程式語言的慣用做法是需要引入臨時變量,大多數代碼類似如下方式:

「雪之夢技術驛站」: Go 語言的多變量同時賦值特性體現的更多是一種聲明式編程思想,不關注具體實現,而引入臨時變量這種體現的則是命令式編程思維.

函數的返回值也可以是函數「雪之夢技術驛站」: Go 語言中的函數是一等公民,不僅函數的返回值可以是函數,參數,變量等等都可以是函數.

函數的返回值可以是函數,這樣的實際意義在於使用者可以擁有更大的靈活性,有時可以用作延遲計算,有時也可以用作函數增強.

先來演示一下延遲計算的示例:

函數的返回值可以是函數,由此實現類似於 i++ 效果的自增函數.因為 i 的初值是 0,所以每調用一次該函數, i 的值就會自增,從而實現 i++ 的效果.

再小的代碼片段也不應該忘記測試,單元測試繼續走起,順便看一下使用方法.

初始調用 autoIncrease 函數並沒有直接得到結果而是返回了函數引用,等到使用者覺得時機成熟後再次調用返回的函數引用即變量a ,這時候才會真正計算結果,這種方式被稱為延遲計算也叫做惰性求值.

繼續演示一下功能增強的示例:

因為要演示函數增強功能,沒有輸入哪來的輸出?

所以函數的入參應該也是函數,返回值就是增強後的函數.

這樣的話接下來要做的函數就比較清晰了,這裡我們定義 timeSpend 函數: 實現的功能是包裝特定類型的函數,增加計算函數運行時間的新功能並包裝成函數,最後返回出去給使用者.

為了演示包裝函數 timeSpend,需要定義一個比較耗時函數當做入參,函數名稱姑且稱之為為 slowFunc ,睡眠 1s 來模擬耗時操作.

無測試不編碼,繼續運行單元測試用例,演示包裝函數 timeSpend 是如何增強原函數 slowFunc 以實現功能增強?

「雪之夢技術驛站」: 測試結果顯示原函數 slowFunc 被當做入參傳遞給包裝函數 timeSpend 後實現了功能增強,不僅保留了原函數功能還增加了計時功能.

函數嵌套可能是閉包函數不論是引言部分的斐波那契數列生成器函數還是演示函數返回值的自增函數示例,其實這種形式的函數有一種專業術語稱為"閉包".

一般而言,函數內部不僅存在變量還有嵌套函數,而嵌套函數又引用了這些外部變量的話,那麼這種形式很有可能就是閉包函數.

什麼是閉包

如果有一句話介紹什麼是閉包,那麼我更願意稱其為流浪在外的人想念爸爸媽媽!

如果非要用比較官方的定義去解釋什麼是閉包,那隻好翻開https://en.wikipedia.org/wiki/Closure_%28computer_programming%29 看下有關閉包的定義:

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function[a] together with an environment.[1] The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

如果能夠直接理解英文的同學可以略過這部分的中文翻譯,要是不願意費腦理解英文的小夥伴跟我一起解讀中文吧!

閉包是一種技術

第一句話英文如下:

In programming languages, a closure, also lexical closureor function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions.

相應的中文翻譯:

閉包也叫做詞法閉包或者函數閉包,是函數優先程式語言中用於實現詞法範圍的名稱綁定技術.

概念性定義解釋後可能還是不太清楚,那麼就用代碼解釋一下什麼是閉包?

「雪之夢技術驛站」: 程式語言千萬種,前端後端和中臺;心有餘而力不足,大眾化 Js 帶上 Go .

Go 實現斐波那契數列生成器這是開篇引言的示例,直接照搬過來,這裡主要說明 Go 支持閉包這種技術而已,所以並不關心具體實現細節.

單元測試用例函數,連續 10 次調用斐波那契數列生成器,輸出斐波那契數列中的前十位數字.

Js 實現斐波那契數列生成器仿照 Go 語言的實現方式寫一個 Js 版本的斐波那契數列生成器,相關代碼如下:

同樣的,仿造測試代碼寫出 Js 版本的測試用例:

不僅僅是 Js 和 Go 這兩種程式語言能夠實現閉包,實際上很多程式語言都能實現閉包,就像是面向對象編程一樣,也不是某種語言專有的技術,唯一的區別可能就是語法細節上略有不同吧,所以記住了: 閉包是一種技術!

閉包存儲了環境

第二句英文如下:

Operationally, a closure is a recordstoring a function[a] together with an environment.

相應的中文翻譯:

在操作上,閉包是將函數[a]與環境一起存儲的記錄。

第一句我們知道了閉包是一種技術,而現在我們有知道了閉包存儲了閉包函數所需要的環境,而環境分為函數運行時所處的內部環境和依賴的外部環境,閉包函數被使用者調用時不會像普通函數那樣丟失環境而是存儲了環境.

如果是普通函數方式打開上述示例的斐波那契數列生成器:

可想而知,這樣肯定是不行的,因為函數內部環境是無法維持的,使用者每次調用 fibonacciWithoutClosure 函數都會重新初始化變量 a,b 的值,因而無法實現累加自增效果.

很顯然,函數內部定義的變量每次運行函數時都會重新初始化,為了避免這種情況,在不改變整體實現思路的前提下,只需要提升變量的作用範圍就能實現斐波那契數列生成器函數:

此時再次運行 10 次斐波那契數列生成器函數,如我們所願生成前 10 位斐波那契數列.

所以說普通函數 fibonacciWithoutClosure 的運行環境要麼是僅僅依賴內部變量維持的獨立環境,每次運行都會重新初始化,無法實現變量的重複利用;要麼是依賴了外部變量維持的具有記憶功能的環境,解決了重新初始化問題的同時引入了新的問題,那就是必須定義作用範圍更大的外部環境,增加了維護成本.

既然函數內的變量無法維持而函數外的變量又需要管理,如果能兩者結合的話,豈不是皆大歡喜,揚長補短?

對的,閉包基本上就是這種實現思路!

斐波那契數列生成器函數 fibonacci 的返回值是匿名函數,而匿名函數的返回值就是斐波那契數字.

如果不考慮函數內部實現細節,整個函數的語義是十分明確的,使用者初始化調用 fibonacci 函數時得到返回值是真正的斐波那契生成器函數,用變量暫存起來,當需要生成斐波那契數字的時候再調用剛才暫存的變量就能真正生成斐波那契數列.

現在我們再好好比較一下這種形式實現的閉包和普通函數的區別?

閉包函數 fibonacci 的內部定義了變量 a,b,最終返回的匿名函數中使用了變量 a,b,使用時間接生成斐波那契數字.普通函數 fibonacciWithoutClosure 的外部定義了變量 a,b,調用該函數直接生成斐波那契數字.閉包函數是延遲計算也就是惰性求值而普通函數是立即計算,兩者的調用方式不一樣.但是如果把視角切換到真正有價值部分,你會發現閉包函數隻不過是普通函數嵌套而已!

只不過 Go 並不支持函數嵌套,只能使用匿名函數來實現函數嵌套的效果,所以上述示例是會直接報錯的喲!

但是某些語言是支持函數嵌套的,比如最常用的 Js 語言就支持函數嵌套,用 Js 重寫上述代碼如下:

斐波那契數列生成器函數是 fibonacciDeduction,該函數內部真正實現生成器功能的卻是 fibonacciGenerator 函數,正是這個函數使用了變量 a,b ,相當於把外部變量打包綁定成運行環境的一部分!

「雪之夢技術驛站」: 閉包並不是某一種語言特有的技術,雖然各個語言的實現細節上有所差異,但並不妨礙整體理解,正如定義的第二句那樣: storing a **function**[a] together with an **environment**.

環境關聯了自由變量

第三句英文如下:

The environment is a mapping associating each free variableof the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created

相應的中文翻譯:

環境是一種映射,它將函數的每個自由變量(在本地使用但在封閉範圍內定義的變量)與創建閉包時名稱綁定到的值或引用相關聯。

環境是閉包所處的環境,這裡強調的是外部環境,更確切的說是相對於匿名函數而言的外部變量,像這種被閉包函數使用但是定義在閉包函數外部的變量被稱為自由變量.

「雪之夢技術驛站」: 由於閉包函數內部使用了自由變量,所以閉包內部的也就關聯了自由變量的值或引用,這種綁定關係是創建閉包時確定的,運行時環境也會一直存在並不會發生像普通函數那樣無法維持環境.

自由變量這裡使用了一個比較陌生的概念: 自由變量(在本地使用但在封閉範圍內定義的變量)

很顯然,根據括號裡面的注釋說明我們知道: 所謂的自由變量是相對於閉包函數或者說匿名函數來說的外部變量,由於該變量的定義不受自己控制,所以對閉包函數自己來說就是自由的,並不受閉包函數的約束!

那麼按照這種邏輯繼續延伸猜測的話,匿名函數內部定義的變量豈不是約束變量?對於閉包函數而言的自由變量對於定義函數來說豈不是約束變量?

「雪之夢技術驛站」: 這裡的變量 a,b 相對於函數 fibonacciWithoutClosure 來說,是不是自由變量?或者說全局變量就是自由變量,對嗎?

值或引用

變量 a,b 定義在函數 fibonacci 內部,相對於匿名函數 func() int 來說是自由變量,在匿名函數中直接使用了變量 a,b 並沒有重新複製一份,所以這種形式的環境關聯的自由變量是引用.

再舉個引用關聯的示例,加深一下閉包的環境理解.

上述示例的 countByClosureButWrong 函數內部定義了變量數組 arr ,存儲的是匿名函數而匿名函數使用的是循環變量i .

這裡的循環變量的定義部分是在匿名函數的外部就是所謂的自由變量,變量 i 沒有進行拷貝所以也就是引用關聯.

運行這種閉包函數,最終的輸出結果都是 4 4 4,這是因為閉包的環境關聯的循環變量 i 是引用方式而不是值傳遞方式,所以閉包運行結束後的變量 i 已經是 4.

除了引用傳遞方式還有值傳遞方式,關聯自由變量時拷貝一份到匿名函數,使用者調用閉包函數時就能如願綁定到循環變量.

「雪之夢技術驛站」: 自由變量 i 作為參數傳遞給匿名函數,而 Go 中的參數傳遞只有值傳遞,所以匿名函數使用的變量 n 就可以正確綁定循環變量了,這也就是自由變量的值綁定方式.

「雪之夢技術驛站」: 自由變量通過值傳遞的方式傳遞給閉包函數,實現值綁定環境,正確綁定了循環變量 1 2 3 而不是 4 4 4

訪問被捕獲自由變量

第四句英文如下:

Unlike a plain function, a closure allows the function to access those captured variablesthrough the closure's copies of their values or references, even when the function is invoked outside their scope.

相應的中文翻譯:

與普通函數不同,閉包允許函數通過閉包的值的副本或引用訪問那些被捕獲的變量,即使函數在其作用域之外被調用

閉包函數和普通函數的不同之處在於,閉包提供一種持續訪問被捕獲變量的能力,簡單的理解就是擴大了變量的作用域.

自由變量 a,b 的定義發生在函數 fibonacci 體內,一般而言,變量的作用域也僅限於函數內部,外界是無法訪問該變量的值或引用的.

但是,閉包提供了持續暴露變量的機制,外界突然能夠訪問原本應該私有的變量,實現了全局變量的作用域效果!

「雪之夢技術驛站」: 普通函數想要訪問變量 a,b 的值或引用,定義在函數內部是無法暴露給調用者訪問的,只能提升成全局變量才能實現作用域範圍的擴大.

由此可見,一旦變量被閉包捕獲後,外界使用者是可以訪問這些被捕獲的變量的值或引用的,相當於訪問了私有變量!

怎麼理解閉包

閉包是一種函數式編程中實現名稱綁定的技術,直觀表現為函數嵌套提升變量的作用範圍,使得原本壽命短暫的局部變量獲得長生不死的能力,只要被捕獲到的自由變量一直在使用中,系統就不會回收內存空間!

知乎上關於閉包的眾多回答中,其中有一個回答言簡意賅,特意分享如下:

我叫獨孤求敗,我在一個山洞裡,裡面有世界上最好的劍法,還有最好的武器。我學習了裡面的劍法,拿走了最好的劍。離開了這裡。我來到這個江湖,快意恩仇。但是從來沒有人知道我這把劍的來歷,和我這一身的武功。。。那山洞就是一個閉包,而我,就是那個山洞裡唯一一個可以與外界交匯的地方。這山洞的一切對外人而言就像不存在一樣,只有我才擁有這裡面的寶藏!

這也是閉包定義中最後一句話表達的意思: 山洞是閉包函數,裡面的劍法和武器就是閉包的內部環境,而獨孤求敗劍客則是被捕獲的自由變量,他出生在山洞之外的世界,學成歸來後獨自闖蕩江湖.從此江湖上有了獨孤求敗的傳說和那把劍以及神秘莫測的劍法.

掌握閉包了麼

問題: 請將下述普通函數改寫成閉包函數?

回答: 閉包的錯誤示例以及正確示例

那麼,問題來了,原本普通函數就能實現的需求更改成閉包函數實現後,一不小心就弄錯了,為什麼還需要閉包?

閉包歸納總結

現在再次回顧一下斐波那契數列生成器函數,相信你已經讀懂了吧,有沒有看到閉包的影子呢?

但是,有沒有想過這麼一個問題: 為什麼需要閉包,閉包解決了什麼問題?

閉包不是某一種語言特有的機制,但常出現在函數式編程中,尤其是函數佔據重要地位的程式語言.閉包的直觀表現是函數內部嵌套了函數,並且內部函數訪問了外部變量,從而使得自由變量獲得延長壽命的能力.閉包中使用的自由變量一般有值傳遞和引用傳遞兩種形式,示例中的斐波那契數列生成器利用的是引用而循環變量示例用的是值傳遞.Go 不支持函數嵌套但支持匿名函數,語法層面的差異性掩蓋不了閉包整體的統一性.「雪之夢技術驛站」: 由於篇幅所限,為什麼需要閉包以及閉包的優缺點等知識的相關分析打算另開一篇單獨討論,敬請期待...

相關資料參考

https://www.liaoxuefeng.com/wiki/1022910821149312/1023021250770016https://www.zhihu.com/question/34210214https://lotabout.me/2016/thoughts-of-closure/如果你覺得本文對你有所幫助,歡迎點讚評論和轉發,來一波素質三連吧! 偷偷告訴你,點擊了解更多可以獲得最佳閱讀體驗喲!

相關焦點

  • go 學習筆記之學習函數式編程前不要忘了函數基礎
    所以接下來我們一邊複習一邊學習函數的基本特點,為接下來理解函數式編程打下基礎,關於函數的基礎語言可參考 go 學習筆記之值得特別關注的基礎語法有哪些函數的基礎語法和高級特性下面以最基本四則運算為例,貫穿全文講解函數的基本語法和高級特性
  • go 學習筆記之解讀什麼是defer延遲函數
    一般來說,我們需要控制結束語句,在合適的位置和時機控制結束語句,手動保證整個程序有始有終,不遺漏清理收尾操作.無 defer 的文件拷貝有 defer 的文件拷貝上述示例代碼簡單展示了 defer 關鍵字的基本使用方式,顯著的好處在於 Open/Close 是一對操作,不會因為寫到最後而忘記 Close 操作,而且連續依賴時也能正常保證延遲時機.
  • 解密 Go 語言之反射 reflect
    今天是 2020 年的最後一天,讓我們一起繼續愉快的學習吧 :)。在所有的語言中,反射這一功能基本屬於必不可少的模塊。雖說 「反射」 這個詞讓人根深蒂固,但更多的還是 WHY。反射到底是什麼,反射又是基於什麼法則實現的?
  • 第55p,閉包函數,函數知識的綜合運用
    大家好,我是楊數Tos,這是《從零基礎到大神》系列課程的第55篇文章,第三階段的課程:Python進階知識:Python進階知識:詳細講解Python中的函數(八)====> 函數的嵌套調用之閉包函數。
  • 閉包,閉包
    一、閉包的定義:閉包是關係的一種特殊運算,運算結果依然是關係。
  • Go語言學習筆記之字符串一
    Go語言是一個年輕人,身上擁有c++,java,python等語言的特點。在網絡通信、並發和並行編程擁有極好的體驗,當然不僅僅在這上上面,還有網絡編程,web應用,應用下載等有著非常大的潛力。這裡列舉一些 Go 語言的特點: 簡化問題,易於學習 內存管理,簡潔語法,易於使用 快速編譯,高效開發 高效執行 並發支持,輕鬆駕馭, 靜態類型 標準類庫,規範統一 易於部署 文檔全面 免費開源學習go語言有幾天了,今天突然想到把學的寫成筆記,記錄一下。如有不正確的請指教。
  • Go語言的學習筆記(第二章)
    ,但是如果我們直接在代碼中通過內存地址去操作變量的話,代碼的可讀性會非常差而且還容易出錯,所以我們就利用變量將這個數據的內存地址保存起來,以後直接通過這個變量就能找到內存上對應的數據了。stringvar age intvar isOk bool批量聲明每聲明一個變量就需要寫
  • 《跟著考霸記筆記》:「會記憶=會學習=會成功」是普遍法則
    馬雲說過:人如果停止了學習,就開始走向失敗。這是一個靠證吃飯的時代,這是一個需要不停學習的時代。在這個充滿不確定性的世界裡活著,你越想尋求安逸,就會越來越危險。時代在飛速地發展,只有在「變化」中學習,一直向前,才不會害怕歲月的侵襲。
  • 教你如何做一個賞心悅目的筆記
    接下來即將迎來的想必便是高考還有開學,大家都知道筆記但是自己並不會做筆記,老師講過課後不知道講的是什麼,課上的知識點左耳進右耳出,應該如何做一個賞心悅目的筆記,跟隨我們一起來看看。反之則選擇普通色的筆(黑色籤字筆)作為普通內容的書寫,這樣一來在複習筆記的時候就可以清楚看清重點內容是什麼,複習的時候可以節省時間去找重點。
  • 深度學習之用Go語言構建一個屬於自己的神經網絡(附代碼)
    從頭開始創建自己的神經網絡將會更好地了解神經網絡內部發生的情況,對之後學習算法的工作更加了解。什麼是感知器?感知器由弗蘭克·羅森布拉特於1958 年發明,是最簡單的神經網絡,由n個輸入,一個神經元和一個輸出組成,其中n是數據集的特徵數量。
  • 解讀Python函數閉包的概念及作用域
    函數的引用是什麼呢?當我們定義一個函數時,不管是父函數還是父函數體內的嵌套函數。Python解釋器都會為定義的函數分配內存空間,用於存儲函數的代碼、使用的變量等等,該內存的地址被賦值給函數名稱所標識的存儲單元,函數調用者可以通過函數名稱所標識的存儲單元找到函數的內存地址,並執行該函數。由此看來,函數名稱也是一個變量,它存儲了函數的內存地址。
  • 學習筆記的 5作用、4誤區、3分類、6要點
    記筆記的意義?每個人都記錄過筆記,但有趣的是,從來沒有哪個學校把記錄筆記當作一個課程。原因很多,當中最重要的原因可能是因為學習內容、傳達載體、以及學習者個人的習慣和能力的差異。過於簡單,成為一個授課目錄因為很多老師分發講義,PPT等,記錄者認為沒有必要再記一次,形成了一個目錄沒有任何意義。2. 什麼都記,拍照式的記錄機械的複寫,把所有內容一股腦的記錄。甚至都影響了傾聽思考,所謂拍照式的筆記。沒有3.
  • 中考化學基礎20講,攻克這些,後面的學習就能快起來
    現在跟著我把這20講的內容完全掌握,哪怕你花掉一個月時間,後面的一個多月也夠你學會其它的部分了。這20講是從理論上把化學的概念理清,讓你明白那些符號都是什麼,這樣學起來才能真正透徹。當然也是在初中所能接受的範圍內講解清楚,有些概念還是繞過去的,即使如此,也大大有利於後面的學習。另外,這部分內容安排了很多需要熟練的東西。
  • 框架法學習示例:如何從邏輯學之中設計出一個簡單的框架!
    面對一本書要如何學習呢?個人採取框架法來學習,並以如何學習邏輯學,作了一個完整的示例,這個示例呢,其實涉及到個人的另一個專欄:從0到1設計一個簡單的邏輯框架!學習邏輯學,最後輸出什麼呢,輸出一個框架,這個框架長成啥樣子呢,看下圖:從0到設計一個簡單的框架,只是使用「建構符合認知機制的學習方法論」中的一部分方法,那就是框架法!設計一個框架來組織邏輯學所涉及的各個概念!
  • 掌握六個步驟,做好讀書筆記
    在做讀書筆記時,許多人都是書上有什麼,就摘抄什麼,其讀書筆記充其量只是一個摘抄本。有的人雖然記著讀書筆記,但只是在讀書時記下了,之後再也沒有翻過,更談不上去整理和複習,去應用了。這樣的讀書筆記絲毫沒有什麼用處,最終使讀書筆記成了一種形式和一種浪費。把書上的內容變成自己的知識,才能體現讀書筆記真正的價值和作用。那麼,如何記讀書筆記?
  • R相關與回歸學習筆記(三十五)——樣條函數變換、線性可加模型(一)
    m個節點的三次樣條函數需要n+4個參數, 因為每段需要4個參數, m+1段需要4m+4個參數, 而在個節點上連續、一階導數連續、二階導數連續構成三個約束條件, 所以參數個數為m+4個。自然樣條函數假定函數在最左邊一段和最右邊一段為線性函數, 這樣m個節點需要m+2個參數。
  • 娃兒總是搞不清楚,和小新一起學習吧
    上節課我們學習了漢語拼音的分類,還記得阿狗同學提出的問題嗎?小朋友課後有沒有發現什麼問題呢?小新來給大家一點提示,複韻母包括ai 、ei、 ui 、ao、 ou、 iu 、ie 、üe、 er小新,小新我知道了,阿狗同學你發現什麼問題了?來給大家說一下,我記得上節課小新帶著大家學習的時候,說它是特殊韻母,小新,它到底是複韻母還是特殊韻母啊?我的腦袋現在有點暈。阿狗同學你真棒,問題就在這裡。
  • 初一學習方法:做筆記
    做筆記是門很少有人研究的學問。會做筆記的同學可能上課時記得並不多,但很有成效。有些同學的筆記只有自己看得懂,但也很有效。相反,有的同學筆記記得很多,上課時幾乎一直在記筆記,不僅效果差,甚至會影響聽課效果。所以學會有效地做筆記對於每一個同學來說都是很重要的。   1.如何記課堂筆記?
  • 怎麼學好數學(一)——怎麼記筆記
    對學生來說,上課記筆記是非常重要的一個學習方式,一份良好的筆記不僅記錄了上課講的內容,更重要的是記錄了自己不會的知識點便於課後繼續專研,還可以供複習使用……總之記筆記有很多好處,但在上課的時候,你應該什麼時候記?記哪些內容呢?
  • 如何寫好文獻綜述,這幾步需要弄清楚
    因為,寫文獻綜述就意味著要看很多相關文獻,要做文獻筆記,任務量很大,這也是很多同學最感到頭疼的一點。當然,也有少數同學覺得寫文獻綜述很簡單,認為把別人的觀點複製過來就可以了。這種想法當然是不正確的。事實上寫文獻綜述之前,這幾步同學們需要弄清楚。