十分鐘了解 18 個冷門編程概念
作為開發者,我們需要不斷學習新的術語、技術和最佳實踐。但是,如果有人告訴你還有許多你甚至不知道的概念,而且這些概念可能會改變你編碼和思考的方式,你會怎么想?無論你是初學者還是經驗豐富的開發者,這 18 個冷門概念都將幫助你提升水平。本文就會帶你深入了解這些概念,示例代碼將基于 JS 和 Python。
1. Thunk:善用拖延癥
你有過把事情拖到最后一刻才做的經歷嗎?thunk 正是如此,它將函數的執行推遲到絕對必要的時候。
想象一下,有一項計算成本很高的任務,但暫時不確定是否需要計算結果。與其提前計算,不如用 thunk 將其封裝起來。
const thunk = () => 5 + 10;
console.log(thunk()); // 只在調用時進行計算
2. Monad(單子):代碼的安全網
Monad 就像是函數的安全網,幫你實現鏈式操作并處理意外行為(如錯誤或空值),而不會導致整個程序崩潰。如果你正在處理異步數據,可能已經在不知不覺中用到了 monad!
new Promise((resolve) => resolve(5))
.then(value => console.log(value)) // 輸出: 5
Monad 看起來很神秘,但可以把它們想象成沿著管道安全傳遞數據的容器。
3. Closure(閉包):代碼記憶
試想一下,如果過去的自己能給未來的自己留下一段回憶會怎么樣,這正是 closure(閉包)的作用,它允許函數 "記住" 變量創建時候的上下文。
def counter():
count = 0
def _():
nonlocal count
count += 1
return count
return _
increment = counter()
print(increment())
print(increment())
print(increment())
#1
#2
#3
4. Memoization:讓我們提高效率,好嗎?
有沒有反復問同一個問題的經歷?很煩人吧?計算機也是這么想的。Memoization 通過存儲結果解決了這個問題,這樣就不必重復進行昂貴的計算。
def fib(n, memo={}):
if n in memo:
return memo[n]
if n < 2:
return n
memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
return memo[n]
fib(100)
#354224848179261915075
5. Continuation:未來掌握在自己手中
continuation 就像在代碼中按下 "暫停" 鍵,并將稍后執行下一步,這是許多異步系統背后的秘訣。
function asyncTask(callback) {
setTimeout(() => {
console.log("Task complete");
callback();
}, 1000);
}
asyncTask(() => console.log("Next step"));
1 秒后,箭頭內的代碼 () => { console.log("Task complete"); callback(); } 將被執行。
處理過異步編程嗎?寫過最后的回調函數吧?它就是一個 continuation,是將在未來發生的事情!
6. Idempotence(冪等性):無論做多少次,結果都和第一次一樣
在編程過程中,有些操作無論執行多少次,其行為方式都是一樣的。這就是冪等性 -- 無論調用 API 一次還是 100 次,結果都是一樣的。
GET /user/123 HTTP/1.1
如果一直調用 GET /user/123,得到的永遠是同一個用戶。API 的世界依賴于這一原則,它讓一切都具有可預測性和安全性。
7. Quine(奎因):自我復制的程序
quine 是一種聰明的代碼,能輸出自己的源代碼,就像照鏡子時看到……嗯,代碼正盯著你看。
s = 's = {!r}; print(s.format(s))'; print(s.format(s))
#輸出 => s = 's = {!r}; print(s.format(s))'; print(s.format(s))
8. Zipper:超級結構化導航
在不造成混亂的情況下瀏覽和修改數據結構是一件棘手的事情,直到出現了 zipper,它可以幫助我們高效遍歷和修改結構(如樹),而不會破壞原有結構。
class Zipper:
def __init__(self, left, right):
self.left = left
self.right = right
def move_left(self):
return Zipper(self.left[:-1], [self.left[-1]] + self.right)
def move_right(self):
return Zipper(self.left + [self.right[0]], self.right[1:])
Zipper 是復雜數據結構的導航指南針。
9. Functor(函子):友好的映射
functor 是一種可以映射函數的東西,可以在不接觸容器本身的情況下,對容器中的每個數據進行轉換。它不僅僅是函數式編程,更具備強大的組合能力。
numbers = [1, 2, 3]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9]
Python 中的 list 是函數,允許我們在不改變原始結構的情況下進行映射操作。
10. Tail Call Optimization(尾調用優化):不會造成棧溢出的無限遞歸
尾調用優化(TCO)讓我們在編寫遞歸函數時不必擔心內存不足。如果函數的最后一個操作是調用自身,TCO 可以重復使用當前函數的棧幀。
def factorial(n, acc=1):
if n == 0:
return acc
return factorial(n - 1, acc * n)
注:以上示例只顯示了 TCO 的結構,但請記住 Python 本身并不支持 TCO。
11. Currying(柯里化):請一次只做一件事!
柯里化將一個接受多個參數的函數分解成一系列函數,每個函數只有一個參數。
def add(x):
def inner(y):
return x + y
return inner
add_five = add(5)
print(add_five(3)) # 8
柯里化是獲得靈活性的關鍵 -- 想要應用部分參數?柯里化可以做到。
還可以基于 partial 進行函數柯里化。
from functools import partial
def adder(a, b):
return a + b
two_adder = partial(adder, 2)
two_adder(10)
#12
12. Spectre & Meltdown:困擾你的 CPU
你可能聽說過 Spectre 和 Meltdown 這兩個震驚世界的臭名昭著的漏洞,它們利用了現代處理器優化性能的方式,泄露了敏感數據。
if (untrusted_input < array_size) {
temp = array[untrusted_input * 512];
}
單純追求速度可能會讓事情更糟,投機取巧的執行可能會加快代碼的執行,但有時泄露的信息會超出我們的想象!
13. Homomorphism(同態):保留結構
Homomorphism(同態)是個花哨的詞,指在兩個代數系統之間保留結構的函數。在數學中是很重要的概念,但在編程中轉換數據時也很重要。(最重要的函數式編程概念之一)
numbers = [1, 2, 3, 4]
def square(x):
return x * x
squared_numbers = list(map(square, numbers))
print(squared_numbers)
# Output: [1, 4, 9, 16]
14. Lazy Evaluation(惰性求值):只在需要時
惰性求值會將表達式的求值延遲到需要時才進行,對于提高大型數據集或計算程序的性能非常有用。
def lazy_range(n):
i = 0
while i < n:
yield i
i += 1
for num in lazy_range(5):
print(num)
生成器只在需要時才計算數值,從而節省了內存和處理時間。
thunk 和惰性求值生成器 ?? 有何區別?
- 惰性求值是一種延遲求值表達式的策略,直到實際需要時才進行計算。它可以避免不必要的計算,從而幫助優化性能,尤其是在使用無限數據結構或處理昂貴的操作時。
- Thunk 是一種用于實現惰性求值的特定技術,本質上是一個沒有參數的函數,封裝了計算或表達式,計算會被延遲到 Thunk 被明確調用時執行。
15. Canonicalization(規格化):將數據標準化
Canonicalization(規格化)是將數據轉換為標準或規范化形式的過程,通常用于數據庫和 URL,以確保一致性。
http://example.com
https://example.com
http://www.example.com
規格化可確保所有版本都指向一個唯一首選版本。
16. Side Effect(副作用):超出預期
當函數或表達式修改了其本地環境之外的某些狀態時,就會產生副作用,例如改變全局變量、I/O 操作或修改輸入參數。
def add_to_list(value, lst=[]):
lst.append(value)
return lst
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [1, 2] (unexpected!)
本例中的函數修改了默認參數,導致了意想不到的副作用。
17. Hoisting:將聲明移至頂部
在 JavaScript 中,hoisting 會在編譯階段將變量和函數聲明移到其作用域的頂部。
console.log(x); // 未定義
var x = 5;
即使 x 是在 console.log 之后聲明,JavaScript 也會將聲明提升到頂部,使 x 在定義之前就可以訪問。
18. Monoid(單態):以一致的方式組合數據
monoid (單態)是一種代數結構,具有二元運算和一個標識元素,允許以關聯方式組合數據。
result = ''.join(['a', 'b', 'c'])
print(result) # 'abc'
這里的字符串連接構成了一個以 '' 為標識元素、以 + 為二進制運算的單元。
結論
這些高級編程術語初看起來可能很深奧,但理解了它們可以極大改進編寫代碼的方法。無論是優化性能、安全性還是可讀性,這些概念可以是強大的工具,幫助我們以優雅的方式解決復雜問題。