Jebakan utama adalah bahwa semantik yang mengikat untuk variabel yang tidak terdefinisi — yaitu variabel yang tidak didefinisikan dengan defvardan teman — berubah dengan lexical-binding: Tanpa itu, letmengikat segala sesuatu secara dinamis, tetapi dengan lexical-bindingvariabel yang tidak terdefinisi yang terikat terikat secara leksikal , dan bahkan tereliminasi sepenuhnya jika tidak digunakan dalam lingkup leksikal saat ini .
Kode lama terkadang bergantung pada ini. Untuk menghindari dependensi keras untuk fitur opsional, itu akan mengikat variabel dinamis tanpa memerlukan pustaka yang sesuai atau mendeklarasikan variabel itu sendiri:
(let ((cook-eggs-enabled t))
(cook-my-meal))
Jika fitur memasak adalah opsional, kami tidak ingin memaksakan dependensi yang tidak perlu ke pengguna, jadi kami tidak menggunakan (require 'cook)dan sebaliknya mengandalkan autoloading cook-my-mealfungsi.
Jelas bagi pembaca manusia yang cook-eggs-enabledbukan variabel lokal, tetapi masih merujuk pada beberapa variabel dinamis global dari cookperpustakaan di sini. Tanpa lexical-bindingkode ini berfungsi sebagaimana dimaksud: cook-eggs-enabledterikat secara dinamis, baik didefinisikan atau tidak.
Dengan lexical-bindingbagaimanapun, rusak: cook-eggs-enabledsekarang terikat secara leksikal (dan kemudian dioptimalkan pergi, karena itu tidak digunakan), sehingga variabel global yang dinamis cook-eggs-enabledini tidak pernah tersentuh sama sekali dan masih nilpada saat cook-my-mealdipanggil, jadi kami tidak mengherankan akan memiliki telur setiap dalam makanan kami.
Untungnya, masalah-masalah ini sangat mudah dikenali : Kompiler byte secara alami memperingatkan tentang pengikatan leksikal yang tidak digunakan di sini.
Cara mengatasinya sederhana: Baik menambahkan a (require 'cook)(untuk fitur yang sebenarnya bukan opsional), atau — untuk menghindari dependensi keras — mendeklarasikan variabel tersebut sebagai variabel dinamis dalam kode Anda sendiri . Ada defvarbentuk khusus untuk ini:
(defvar cook-eggs-enabled)
Ini mendefinisikan cook-eggs-enabledsebagai variabel dinamis, tetapi tidak mempengaruhi docstring, load-history(dan dengan demikian find-variabledan teman-teman) atau apa pun, kecuali sifat mengikat variabel.
cook-eggs-enabledtidak terikat ketikaletselesai? Saya cukup yakin saya mengalami bug seperti ini sebelumnya. Defvar terjadi di dalamlet, danletkemudian mengembalikan variabel ke keadaan awal (void).