我想使用一个函数同时更改两个常量,但不知何故它没有生效:
(define p 1)
(define q 1)
(define (change p q)
(set! p (+ p 1))
(set! q (+ q 1)))
这样做是可行的:
#lang racket
(define p 1)
(define q 1)
(define (increment-p-and-q)
(set! p (+ p 1))
(set! q (+ q 1)))
(display (list p q)) ; displays (1 1)
(newline)
(increment-p-and-q) ; mutates p and q
(display (list p q)) ; displays (2 2)
(newline)
当您调用与全局变量具有相同绑定的过程时,该变量将被隐藏。如果您执行 set!
操作,只有本地绑定会发生更改,不会更改全局绑定。
#lang racket
正常工作,但是你没有使用它吗?如果你使用的是不同的语言(DrRacket支持数十种语言),你需要在问题中包含该信息,我们会更新我们的答案。 - Sylwester有可能您使用的语言在过程体内没有隐式的begin
,让我们试着明确地编写它:
(define p 1) ; declare variables as global, so they
(define q 1) ; can be modified inside a procedure
(define (change-vars) ; don't pass them, they won't get modified inside proc
(begin ; use begin to evaluate expressions sequentially from left to right
(set! p (+ p 1))
(set! q (+ q 1)))) ; value of last expression is returned, here's #<void>
它按照预期工作:
p
=> 1
q
=> 1
(change-vars)
p
=> 2
q
=> 2
@Sylwester给出了一个好的、直接的答案。另一个直接的答案是,如果你想让一个函数改变其参数(像C++中的引用参数一样),使用boxes。例如:
(define (change p)
(set-box! p (+ (unbox p) 1)))
(define p (box 1))
(for/list ([i 3])
(change p)
(unbox p))
; => '(2 3 4)
#lang racket
(define p 1)
(define q 1)
(define-syntax-rule (change p q)
(begin
(set! p (+ p 1))
(set! q (+ q 1))))
(display (list p q)) ; displays (1 1)
(newline)
(change p q) ; mutates p and q
(display (list p q)) ; displays (2 2)
(newline)