现在你可以编写自己的静态变量方法了
11281 评价这篇文章:
尚未评分
现在你可以编写自己的静态变量方法了
匿名 2016年6月2日,星期四
静态方法和属性 在 IDL 中已经存在一段时间了,它们在某些时候确实变得很有用。它们为传统的基于例程的 IDL 调用提供了一个便捷的现代替代方案。你可能已经创建了带有静态方法的自己的类,但你知道可以向 IDL 的类中添加自己的方法吗?这在 IDL 的变量静态方法中最为有用。
变量是否大于 10?
让我们尝试一个基本的例子。我有一个 IDL 变量,我想知道该变量是否大于 10。我将从为 IDL_Variable 编写一个新方法开始,我将其称为::IsGreaterThanTen
function IDL_Variable::IsGreaterThanTen, var
虽然这个方法在被变量静态调用时不接受任何参数,但该方法将包含一个参数,即输入变量,在本例中是 var。
result = variable.IsGreaterThanTen()
顾名思义,这个方法需要定义为静态的。这是在 compile_opt 语句中完成的。和往常一样,建议在 compile_opt 语句中也使用 "idl2",并且如果你希望该方法看起来是内置的,那么也使用 "hidden"。
这个方法的其余部分很简单。首先检查变量是否确实是数字,然后执行不等式,返回结果。
function IDL_Variable::IsGreaterThanTen, var
compile_opt idl2, hidden, static
; 如果不是数字,则不大于十。
if ~Isa(var, /NUMBER) then begin
return, 0b
endif
return, var gt 10
end
是州还是省?
这是一个更有用的例子。不久前,我需要一种方法来确定给定的字符串是否是有效的美国州或加拿大省的缩写。这正是为 IDL_String 编写新的静态方法会很方便的时候。
function IDL_String::IsaStateOrProvince, str
compile_opt idl2, hidden, static
abbrevList = ['AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', $
'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', $
'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', $
'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', $
'VA', 'WA', 'WV', 'WI', 'WY', 'AB', 'BC', 'MB', 'NB', 'NL', 'NT', 'NS', $
'NU', 'ON', 'PE', 'QC', 'SK', 'YT']
!null = Where(abbrevList.Matches(str), count)
return, count gt 0
end
(请注意,从技术上讲,其中一些是地区而不是省份。DC 也在这个列表中,但这就是我期望的功能。)
好处
现在我可以把这个添加到我的个人代码库中。相比于一个包含许多可能互不相关的例程的库,我更倾向于这种方式,因为它是一种将静态方法代码捆绑到同一文件中的合理方式(即,将与 IDL_String 相关的代码保存在同一文件中)。这使我将来更容易查找和跟踪代码。此外,我发现调用
result = state.IsaStateOrProvince()
比传统的例程调用
result = IsaStateOrProvince(state)
更直观。我认为这可能是因为静态调用方式是从左到右阅读的。
这个概念是我几年前写的这篇博客的主题。
此外,将例程移到特定的类中释放了主命名空间。例如,我可以写一个不同的 IsaStateOrProvince 例程来做不同的事情,同样,我可以在另一个类上写一个 ::IsaStateOrProvince 方法。这两者都不会干扰上面的例子。
缺点
将例程编写为静态方法的一个小缺点是,你不能直接对不是变量的值调用该方法,这意味着你不能调用
result = 'NY'.IsaStateOrProvince()
因为你会得到一个语法错误。但是,如果你在前面简单地加上 "IDL_String" 和 "点语法",那么它就可以工作:
result = IDL_String.IsaStateOrProvince('NY')
这与重载一个类不同。 重载一个类涉及编写一个新的子类,它继承该类,然后重写继承类的方和/或添加新方法。IDL 的一些类,例如 IDL_Object,其目的就是作为用户编写类的超类来使用。尽管 IDL 变量类并非专门为被重载而设计,但你可以重载任何你想要的类。
另一篇博客文章专门介绍了重载 IDL 的内置类,其中提供了一个重载 IDL LIST 的例子。
![]()
警告! 不要将其保存到名为 IDL_String__Define 或 IDL_Variable__Define 或任何其他静态类名的文件中。相反,你需要将其放入一个不同名称的文件中,该文件作为库文件使用。因此,你可能需要在应用程序开始时使用 RESOLVE_ROUTINE 编译该文件或从保存文件中恢复它。换句话说,将其视为一个包含多个例程的库文件。
举个例子,我把我的 IDL_String::IsaStateOrProvince 方法保存到了一个名为 "bens_strings.pro" 的文件中,这可能永远不会与 IDL 中的其他文件名冲突。
![]()
附加声明: 重要的是要记住,你仍然在与 IDL 共享命名空间,IDL 的静态方法永远不应被用户编写的方法覆盖。在命名新方法时,你需要非常小心,确保它们的名称不与现有的 IDL 方法冲突。IDL 可能会在未来的版本中引入新的静态变量方法,这可能会与你编写的内容发生冲突。因此,在安装新版本的 IDL 时,务必检查“What's New”帮助主题。
当然,这对于任何用户编写的代码都是如此,因为你总是与 IDL 共享命名空间,但在这种低级别上,这一点格外重要。
我可能永远不建议尝试重载任何这些静态类的::GetProperty 方法来尝试添加你自己的静态属性。只坚持使用方法。
编辑: 我最近了解到,也可以将方法放入名为 [类名]__[方法名].pro 的文件中。例如在上面的例子中,我可以编写一个名为 idl_string__isastateorprovince.pro 的文件(类名和方法名之间有两个下划线),IDL 将自动编译它。这样就无需手动编译/恢复辅助文件了。