emacs - 通过 cl-function 传递回调
问题描述
我正在尝试使用来自 REST API的优秀request.el库请求数据:
(request
"http://httpbin.org/get"
:params '(("key" . "value") ("key2" . "value2"))
:parser 'json-read
:success (function*
(lambda (&key data &allow-other-keys)
(message "I sent: %S" (assoc-default 'args data)))))
效果很好。作为一个 lisp 新手,我真的不知道function*
它在这里做了什么,我只是从request.el
-examples 中得到的。
然后我尝试将此调用包装在一个函数中以减少样板文件,如下所示:
(defun my/do-request (callback)
(request
"http://httpbin.org/get"
:params '(("key" . "value") ("key2" . "value2"))
:parser 'json-read
:success callback))
(my/do-request (lambda (data)
(message "got data: %s" data)))
但是回调没有被调用?我也尝试像这样传递回调:
(defun my/do-request (callback)
(request
"http://httpbin.org/get"
:params '(("key" . "value") ("key2" . "value2"))
:parser 'json-read
:success (function*
(lambda (&key data &allow-other-keys)
(callback data)))))
结果相同。我想我可能需要在这里进行词法绑定,但这也无济于事。
我怎样才能在这里减少样板代码?
解决方案
调用新函数时,通常最好使用与原来完全相同的值进行尝试:
(my/do-request
(function*
(lambda (&key data &allow-other-keys)
(message "I sent: %S" (assoc-default 'args data)))))
以上打印所需的消息。
第一种方法
您按如下方式调用代码,但没有打印任何内容:
(my/do-request (lambda (data)
(message "got data: %s" data)))
事实证明有一个错误,但不幸的是它没有到达用户。如有疑问,您应该启用调试器:
(setf debug-on-error t)
您可以在执行( )*scratch*
之后在缓冲区或 minibuffer中评估上述内容。M-:eval-expression
然后,当您重新评估呼叫时,应显示以下内容:
Debugger entered--Lisp error: (wrong-number-of-arguments (lambda (data) (message "got data: %s" data)) 8)
(lambda (data) (message "got data: %s" data))(:data ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . .....) (url . "http://httpbin.org/get?key=value&key2=value2")) :symbol-status success :error-thrown nil :response [cl-struct-request-response 200 nil ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . .....) (url . "http://httpbin.org/get?key=value&key2=value2")) nil success "http://httpbin.org/get?key=value&key2=value2" nil (:params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response #0) #<killed buffer> "HTTP/1.1 200 OK\nConnection: keep-alive\nServer: gunicorn/19.8.1\nDate: Thu, 05 Jul 2018 11:44:15 GMT\nContent-Type: application/json\nContent-Length: 249\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\nVia: 1.1 vegur\n" nil curl nil])
apply((lambda (data) (message "got data: %s" data)) (:data ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) :symbol-status success :error-thrown nil :response [cl-struct-request-response 200 nil ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) nil success "http://httpbin.org/get?key=value&key2=value2" nil (:params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response #1) #<killed buffer> "HTTP/1.1 200 OK\nConnection: keep-alive\nServer: gunicorn/19.8.1\nDate: Thu, 05 Jul 2018 11:44:15 GMT\nContent-Type: application/json\nContent-Length: 249\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\nVia: 1.1 vegur\n" nil curl nil]))
apply(apply (lambda (data) (message "got data: %s" data)) (:data ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) :symbol-status success :error-thrown nil :response [cl-struct-request-response 200 nil ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) nil success "http://httpbin.org/get?key=value&key2=value2" nil (:params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response #1) #<killed buffer> "HTTP/1.1 200 OK\nConnection: keep-alive\nServer: gunicorn/19.8.1\nDate: Thu, 05 Jul 2018 11:44:15 GMT\nContent-Type: application/json\nContent-Length: 249\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\nVia: 1.1 vegur\n" nil curl nil]))
request--safe-apply((lambda (data) (message "got data: %s" data)) (:data ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) :symbol-status success :error-thrown nil :response [cl-struct-request-response 200 nil ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) nil success "http://httpbin.org/get?key=value&key2=value2" nil (:params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response #1) #<killed buffer> "HTTP/1.1 200 OK\nConnection: keep-alive\nServer: gunicorn/19.8.1\nDate: Thu, 05 Jul 2018 11:44:15 GMT\nContent-Type: application/json\nContent-Length: 249\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\nVia: 1.1 vegur\n" nil curl nil]))
request--callback(#<killed buffer> :params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response [cl-struct-request-response 200 nil ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) nil success "http://httpbin.org/get?key=value&key2=value2" nil (:params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response #0) #<killed buffer> "HTTP/1.1 200 OK\nConnection: keep-alive\nServer: gunicorn/19.8.1\nDate: Thu, 05 Jul 2018 11:44:15 GMT\nContent-Type: application/json\nContent-Length: 249\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\nVia: 1.1 vegur\n" nil curl nil])
apply(request--callback #<killed buffer> (:params (("key" . "value") ("key2" . "value2")) :parser json-read :success (lambda (data) (message "got data: %s" data)) :error #[128 "\302\300\303\301\"\"\207" [request-default-error-callback ("http://httpbin.org/get") apply append] 6 "\n\n(fn &rest ARGS2)"] :url "http://httpbin.org/get?key=value&key2=value2" :response [cl-struct-request-response 200 nil ((args (key . "value") (key2 . "value2")) (headers (Accept . "*/*") (Accept-Encoding . "deflate, gzip") (Connection . "close") (Host . "httpbin.org") (User-Agent . "curl/7.55.1")) (origin . ...) (url . "http://httpbin.org/get?key=value&key2=value2")) nil success "http://httpbin.org/get?key=value&key2=value2" nil #0 #<killed buffer> "HTTP/1.1 200 OK\nConnection: keep-alive\nServer: gunicorn/19.8.1\nDate: Thu, 05 Jul 2018 11:44:15 GMT\nContent-Type: application/json\nContent-Length: 249\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\nVia: 1.1 vegur\n" nil curl nil]))
request--curl-callback(#<process request curl> "finished\n")
根据文档,回调函数应该是可变的,这意味着以下工作:
(lambda (&rest args) (message "got data: %s" args))
但是,你会看到太多的数据。
参数作为键/值对传递。为了获取与:data
符号关联的数据,您必须执行以下操作:
(lambda (&rest args)
(message "got data: %s" (getf args :data)))
结果值是一个关联列表,您可以从中访问'args
条目,如上面所做的(即(assoc-default 'args data)
)。
但是,(getf args :data)
您也可以编写:
(lambda (&key data) ...)
特殊&key
符号用于自动访问与:data
隐式参数列表中关联的值。但是,关键字参数来自Common Lisp,Emacs Lisp 不知道如何&key
开箱处理。这就是为什么有一个(function* ...)
围绕 lambda 的宏。然后您可以选择使用function*
宏或自己处理参数列表,如上所示。这取决于你需要什么。正如文档所建议的,如果你使用&key
,你也应该使用&allow-other-keys
.
第二种方法
在您的第二种方法中,debug-on-entry
设置为t
表示这callback
不是已知函数:
Debugger entered--Lisp error: (void-function callback)
这是因为 Emacs Lisp 是 Lisp-2,也就是说,您不能简单地将参数中给出的函数作为函数调用的第一个元素来调用它。Emacs Lisp 将语法理解为“调用名为回调的函数”,而不是“调用绑定到变量回调的函数对象”。你需要使用funcall
:
(function*
(lambda (&key data &allow-other-keys)
(funcall callback data)))
但是有了以上内容,现在的错误是这callback
是一个未定义的变量。现在,这是由于动态范围。如果您评估以下行并重新评估 defun,代码将按预期工作:
(setf lexical-binding t)
或者,您可以将以下内容作为文件的第一行:
;; -*- lexical-binding: t -*-
推荐阅读
- javascript - 如何使用从服务器获取的数据创建动态 nuxt-link?
- r - 如何在R中找到列的中位数
- routes - 检查路由参数是否等于 sidebar.blade.php 中的“值”
- flutter - Flutter Cupertino 文本字段大小错误
- virtualbox - 在我的 Mac OS 上的虚拟机上缺少 fedora 64 位选项?
- node.js - Sequelize - 嵌套在哪里?
- java - Android 11 存储访问和 Java 文件库
- python - 将 PYWEBIO 转换为公共网址
- sql - 更改 Beekeeper SQL 上的“钱”符号
- object-detection-api - 使用 CenterNet HourGlass104 1024x1024 的对象检测器出现问题