【问题标题】:How can Applescript objects be referenced before they are defined?Applescript 对象在定义之前如何被引用?
【发布时间】:2014-11-17 12:47:44
【问题描述】:

有人知道为什么这个applescript 有效吗?我不理解为什么。该脚本生成三个对话框,其中包含相同的消息:“Hi There”。我有两个问题:

1) 如何在定义 i 之前将 j 和 k 设置为引用 i?

2) 为什么 r 不引用 test2 中定义的 i?

on test1()
  return get a reference to i
end test

on run
  set j to test1()
  set k to a reference to i
  set i to "Hi there"
  display dialog j
  display dialog k
  test2()
end run

on test2()
  set i to "now see here"
  set r to a reference to i
  display dialog r
end test2

注意:脚本编辑器是 2.7 版本,AppleScript 版本是 2.4。

【问题讨论】:

标签: reference scope applescript


【解决方案1】:
  1. 您只能创建对对象属性或元素 [s] 或全局变量的引用(一个令人讨厌的错误功能,其行为类似于设计不良的属性),而不是局部变量。例如这些都有效:

    on test2()
        set x to {i:"now see here"}
        set r to a reference to i of x
        display dialog r
    end test2
    
    test2()
    
    on test3()
        set x to {"now see here"}
        set r to a reference to item 1 of x
        display dialog r
    end test3
    
    test3()
    
    on test4()
        script x
            property i : "now see here"
        end script
        set r to a reference to i of x
        display dialog r
    end test4
    
    test4()
    
    
    property i : "now see here"
    
    on test5()
        set r to a reference to i
        display dialog r
    end test4
    
    test5()
    
  2. 隐式或显式 run 处理程序中的所有变量都是全局变量(另一个错误功能),除非显式声明 local。这两个错误功能的组合是您的 run 处理程序示例有效的原因,即使它看起来不应该。

是的,这是一种简陋的语言。但是从好的方面看:它仍然没有 C 指针那么令人头疼。

【讨论】:

  • “隐式或显式运行处理程序中的所有变量都是全局变量”——我认为这并不完全正确。如果不使用a reference toon run 变量中的变量肯定不在作用域内。
  • 哦,是真的。除其他外,a reference to 运算符不会对它们起作用。这并不是说它们本身不会受到一些编译时绑定问题的影响,但这对你来说就是 AppleScript:一直以来的故障错误功能。
  • 您的回答足以回答我的第二个问题。我不同意您将全局变量称为设计不良的属性。全局变量在同一脚本的不同实例之间共享,而属性则不是。我的第一个问题可以通过阅读链接AppleScript Language Guide中的“对象说明符”来回答
  • “全局变量在同一脚本的不同实例之间共享”……以及在完全不相关的脚本实例之间共享,包括导入的库,这些脚本恰好定义了另一个同名的全局变量。这就是它们不好的原因:全局变量可能会在整个程序中产生意想不到的无形交互,而避免这种情况的唯一方法是让程序的每个部分都了解其他所有部分。在相关脚本之间共享状态的正确方法是将该状态存储在其父脚本的属性中。这允许在不破坏封装的情况下共享。
  • 我决定以我自己对第一个问题的回答的形式发布我的所有笔记。如果你不介意,你能不能读一读,让我知道你的想法。更好的是,您可以随意编辑我写的内容。
【解决方案2】:

您基本上不想在脚本中创建“引用”。该类的存在是因为命令返回引用是很常见的。我能想到使用它的唯一优点是您可以创建对对象的引用,而无需明确给出对象的类和值。然后您可以稍后定义该对象。

  1. 因此,在您的示例中,您可以创建对对象的引用,然后再创建它。

  2. 在 test2 处理程序内部,对的引用是一个全局上下文,因此它在运行处理程序中查看标识符 i,而不是在 test2 处理程序内部。

我真的建议不要在你的脚本中使用它们。你觉得你需要什么环境?

【讨论】:

  • 我发布了对您问题的回答,作为我自己对我的问题的回答的一部分。最后,我没有在 AppleScript 中使用引用。我相信我会接受你的建议,并在未来避免它们。
【解决方案3】:

我觉得 foo 在 11 月 18 日回答了我的第二个问题。至于第一个问题,我将提供我自己的解释,这是我在阅读 Object Specifiers 后发现的。以下语句取自我的示例,包含一个隐含的of (get me)

return get a reference to i

为了说明,我将明确地重写语句。

return get a reference to i of (get me)

当执行这些语句中的任何一个时,都会创建一个包含对象说明符的引用对象。 a reference toget 之间的短语是评估的,而是存储在对象说明符中。在这种情况下,短语是i of。评估 get 右侧的内容,并且此结果也存储在对象说明符中。在这种情况下,这个结果是me,它是顶级脚本对象。这就是当引用对象从test1 处理程序返回时,变量i 不必存在的原因。当display dialog j 语句执行时,引用对象被完全评估。此时变量i 必须存在。同样的解释也适用于我的示例中显示的变量k

我确实意识到稍后要评估的文本短语可能实际上并未存储在对象说明符中。至少,我知道该短语已经过解析和语法检查,但 AppleScript 语言指南并没有明确说明语句中未计算的部分是如何存储的。

对我来说,隐式get 的位置似乎有些随意。让我用一些例子来说明我的观点。 (此处为简洁起见,我省略了证明。如果读者无法验证,请告诉我,我会附上证明)

示例 1:如果你写

set r to a reference to i

你得到

set r to get a reference to i of (get me)

例子2:如果你写

set r to a reference to item 2 of i

你得到

set r to get a reference to item 2 of (get i of me)

示例 3:如果你写

set r to a reference to i of me

你得到

set r to get a reference to i of (get me) -- same as Example 1

示例 4:如果你写

set r to a reference to item 2 of i of me

你得到

set r to get a reference to item 2 of i of (get me) -- differs from Example 2

如果您希望设置对对象的引用的内容,我发现了以下限制。由对象说明符包含的短语中的inof 保留关键字的数量必须相等。总数为零或大于一将导致脚本执行错误。下面的例子说明了这一点。

property j : {1, 2, {3, 4}, {{5, {6, 7}}, 8, 9}}

log "Line 1: " & j
set r to a reference to item 3 of j -- phrase is "item 3 of", object is (get j of me)
set contents of r to "aa" -- Succeeds since total count is 1
log "Line 2: " & j

set r to a reference to item 2 of (get item 1 of item 4 of j) -- phrase is "item 2 of", object is (get item 1 of item 4 of (get j of me)) 
set contents of r to "bb" -- Succeeds since total count is 1
log "Line 3: " & j

set j to {1, 2, {3, 4}, {{5, {6, 7}}, 8, 9}}
log "Line 4: " & j
set r to a reference to item 3 of j of me -- phrase is "item 3 of j of", object is (get me)
try
    set contents of r to "cc"  -- Fails since total count is 2 
on error msg
    log "Line 5: " & msg
end try
log "Line 6: " & j

set r to a reference to item 2 of item 1 of item 4 of j -- phrase is "item 2 of item 1 of item 4 of", object is (get j of me) 
try
    set contents of r to "dd" -- Fails since total count  is 3
on error msg
    log "Line 7: " & msg
end try
log "Line 8: " & j

日志输出如下。

(*Line 1: 123456789*)
(*Line 2: 12aa56789*)
(*Line 3: 12aa5bb89*)
(*Line 4: 123456789*)
(*Line 5: Can’t set item 3 of j to "cc".*)
(*Line 6: 123456789*)
(*Line 7: Can’t set item 2 of item 1 of item 4 of {1, 2, {3, 4}, {{5, {6, 7}}, 8, 9}} to "dd".*)
(*Line 8: 123456789*)

set contents of r to "bb” 语句有效,因为我在前面的语句中添加了显式的get。这个forced early evaluation 是对象说明符的一部分。

接下来,我想解决“您认为需要 [使用引用] 的上下文是什么?”这个问题。 11 月 17 日通过调整询问。

最初,我试图找到一种方法让处理程序通过传递的参数返回两个值。下面显示了一个工作示例。

set r to missing value
set s to missing value
FirstAndLast(a reference to r, a reference to s, "now is the time for all good men")
log r
log s

on FirstAndLast(alpha as reference, omega as reference, message as text)
    set contents of alpha to first word of message
    set contents of omega to last word of message
end FirstAndLast

执行此代码会产生日志输出:

(*now*)
(*men*)

上面显示的代码有两个缺点: 1) 变量rs 不能是本地的。 2) 在调用处理程序FirstAndLast 之前,变量rs 必须存在。使用 Applescript 一段时间后,我意识到有更好的方法来实现此代码。一种方法是使用AppleScript Language Guide 中描述的模式分配。使用模式赋值的代码如下所示。

set {r, s} to FirstAndLast("now is the time for all good men")
log r
log s

on FirstAndLast(message as text)
    set alpha to first word of message
    set omega to last word of message
    return {alpha, omega}
end FirstAndLast 

此版本具有三个优点。 1) 这里没有使用参考对象。 2)标识符rs可以表示局部变量、全局变量或属性。 3)如果标识符rs代表变量,则在调用处理程序FirstAndLast之前变量不必存在。

最后,显然处理程序是对象。如果您认为我错了,请解释为什么会执行以下操作。

on test()
    log class of test as text
end test
property y : test
set x to test
log class of x as text
log class of y as text
x()
y()

【讨论】:

    【解决方案4】:

    这不是原始问题的答案。这是对 foo 在 12 月 1 日发表的评论的回应。这是一个示例,说明如何创建同一脚本男孩的两个实例,它们共享一个共同的记录。此外,从 foo 的评论中了解到,我使用记录与所有脚本实例共享属性。我不知道这是否是最好的方法,但至少没有全局变量。

    script mom
        property hair : "blond"
        property shared : {address:"12 walnut st", phone:"555-1234"}
    end script
    
    script boy
        property parent : mom
    end script
    
    script girl
        property parent : mom
    end script
    
    on clone from old given shared:sharedSwitch as boolean : false
        if sharedSwitch then
            set shared to shared of old
            set shared of old to missing value
        end if
        copy old to new
        if sharedSwitch then
            set shared of new to shared
            set shared of old to shared
        end if
        return new
    end clone
    
    property myboy : clone from boy with shared
    
    on run
        log "mom hair is" & tab & tab & hair of mom
        log "boy hair is " & tab & tab & hair of boy
        log "girl hair is " & tab & tab & hair of girl
        log "myboy hair is " & tab & hair of myboy
        set hair of boy to "redhead"
        log "**Set boy hair to redhead**"
        log "mom hair is" & tab & tab & hair of mom
        log "boy hair is " & tab & tab & hair of boy
        log "girl hair is " & tab & tab & hair of girl
        log "myboy hair is " & tab & hair of myboy
        set hair of myboy to "flattop"
        log "**Set myboy hair to flattop**"
        log "mom hair is" & tab & tab & hair of mom
        log "boy hair is " & tab & tab & hair of boy
        log "girl hair is " & tab & tab & hair of girl
        log "myboy hair is " & tab & hair of myboy
        log
        log "mom phone is" & tab & phone of shared of mom
        log "boy phone is" & tab & phone of shared of boy
        log "girl phone is" & tab & phone of shared of girl
        log "myboy phone is" & tab & phone of shared of myboy
        set phone of shared of myboy to "555-9999"
        log "**Set myboy phone to 555-9999**"
        log "mom phone is" & tab & phone of shared of mom
        log "boy phone is" & tab & phone of shared of boy
        log "girl phone is" & tab & phone of shared of girl
        log "myboy phone is" & tab & phone of shared of myboy
    end run
    

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 2023-03-11
      • 2015-07-01
      • 1970-01-01
      • 2013-12-10
      • 2018-11-02
      • 1970-01-01
      • 2020-11-23
      • 2016-03-19
      相关资源
      最近更新 更多