如果我想在运行时选择性地需要模块,我可以使用[dynamic-require
' 1。如果我想要一个已经安装的软件包,这很有用,例如:
(dynamic-require 'racket/match 'match)
这将(假设我已安装racket/match
),需要racket/match
并评估该库中的match
绑定。
但是,当我想要一个本地的,未安装的模块时,我遇到了麻烦。我们假设我有一个名为eat.rkt
的模块,它提供了一个功能:bite
:
#lang racket ;; eat.rkt
(provide bite)
(define (bite) "Nom nom")
现在假设我们要创建一个需要lunch.rkt
的{{1}}模块,然后调用该函数。此外,假设我将它们放在同一目录中:
eat.rkt
这很好,因为我使用了静态需求,但是当我想要#lang racket ;; lunch.rkt
(require "eat.rkt")
(bite) ; => Nom Nom
时,这会崩溃:
dynamic-require
虽然看起来很好,但事实证明#lang racket ;; lunch2.rkt
(define bite (dynamic-require "eat.rkt" 'bite)
(bite) ; => Nom Nom
所需的模块不是基于模块的路径所必需的,而是current-directory
。所以,如果我在定义模块的目录中运行程序,那很好,但是如果我在另一个目录中,一切都会中断:
dynamic-require
显然我可以将$ racket lunch2.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch2.rkt
; default-load-handler: cannot open module file
更改为此模块的目录,如果我知道它在哪里。但如果我不知道这个模块的路径,有什么方法可以得到它吗?或者,更直接地说,是否可以current-directory
模块相对于需要的模块路径?
答案 0 :(得分:2)
define-runtime-path
表单定义了一个在运行时可用的路径,它独立于current-directory
。使用它来定义动态需要的模块的路径,例如:
#lang racket
(require racket/runtime-path)
(define-runtime-path eat "eat.rkt")
(dynamic-require eat 'bite)
答案 1 :(得分:1)
dynamic-require
模块相对于当前模块路径(也就是说保存模块的路径)的最简单方法是获取该模块路径并将其附加到相关模块。
您可以使用#%variable-reference
和variable-reference->module-path-index
执行此操作。 (您可能还希望将variable-reference->resolved-module-path
用于其他情况,但我们不会在此处执行此操作。)通过编写这两个函数,我们可以为正在定义的模块提供module-path-index?
。 (或者一般来说,#%variable-reference
来自的模块。)
所以,我们可以像一个变量:
(define here (variable-reference->module-path-index (#%variable-reference)))
现在剩下的就是将这个here
路径与我们想要的模块的相对路径组合在一起。我们正在寻找build-path
的模块路径类比,如果你愿意的话。
事实证明,我们正在寻找的函数是:module-path-index-join
,它采用基本路径和相对路径并将它们附加在一起。结果将类似于:
(module-path-index-join "eat.rkt" here)
(是的,它是你对build-path
的期望的倒退,但是这个函数的基本路径是第二位。)
生成的模块lunch3.rkt
如下所示:
#lang racket
(define here (variable-reference->module-path-index (#%variable-reference)))
(define bite (dynamic-require (module-path-index-join "eat.rkt" here) 'bite))
现在lunch3.rkt
需要eat.rkt
相对于其定义的位置,而不是基于current-directory
:
$ racket lunch3.rkt
"Nom Nom"
$ cd snacks/
$ racket ../lunch3.rkt
"Nom Nom"
感谢Matthew Flatt帮助解决这个问题。