- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
关于何时一个比另一个更可取,是否有任何“一般规则”?
这个问题的上下文是:我昨天问了一个关于主机协会的不同问题(link)在评论中,我被建议谨慎使用主机关联。原因是通过主机关联,很容易无意中修改变量,因为子例程可以不受限制地访问模块中声明的所有变量。
为了说明这一点,我将使用以下代码示例:
module mod
implicit none
real :: x
contains
subroutine sub(y)
use other_mod, only: a
real, intent(out) :: y
y = a + x
a = a + 1.
x = x + 1.
end subroutine sub
end module mod
a
和x
都在sub
中被修改。但是对于 x
,我需要遍历所有代码才能看到这一点。通过查看 sub
的声明部分可以很容易地看出 a
在 sub
中使用(并且可能被修改)。
从这个意义上说,拥有两种模块似乎更可取:
这完全摆脱了变量的主机关联。
但这似乎不切实际,原因有很多:
最后,所有这些归结为:什么时候将变量声明放在使用它们的同一模块中(以便它们被主机关联使用)更明智,什么时候是将声明外包给单独的模块更明智(以便在需要时通过使用关联使用变量)?
是否有任何一般准则,还是应该根据具体情况来决定?如果是个案,那么选择一个而不是另一个的原因是什么?
最佳答案
Fortran 提供了几种创建、存储、使用和在不同“程序单元”之间传递数据的方法:主程序、外部过程和模块。1 作为您知道,每个程序单元都可以包含内部过程——通过主机关联,这些内部过程可以访问主机中包含的任何变量或过程。这通常被视为一种优势。正如@HighPerformanceMark 在他的评论中已经提到的,何时使用主机关联或使用关联的一般准则是:
use host-association when variables are only (or mainly) used by routines declared in the same module, and use use-association when you want to define variables to be used in many modules
从您的评论来看,听起来您的主程序中的大部分或所有主机变量都被每个内部过程(大约十几个子例程)访问。如果是这样的话,那么主机关联似乎是一个非常合理的选择,而且实际上没有必要显式地将参数传递给每个子例程。另一方面,如果每个子例程实际上只使用变量的一个子集,那么更明确地了解它可能是合理的。
和您一样,我通常不愿意在未在参数列表中声明的过程中使用变量。这部分是因为我喜欢 args 列表是如何 self 记录的,它帮助我推理代码以及如何在其中操作数据。在与其他工作人员协作时,或者如果我已经花了一些时间远离代码并且我对它的内存已经消退时,情况更是如此。然而,我发现几乎没有理由完全避免主机关联,只要您知道它是如何工作的并且有一个策略。
事实上,我倾向于经常使用内部程序和主机关联,尤其是对于短函数/子程序。我发现将宿主粗略地视为“对象”,将其变量视为“属性”,以及非常类似于执行工作的对象的“方法”的任何内部过程是有帮助的。当然,这是在简化事情,但这才是真正的重点。
对于更复杂的程序,我减少了“主”程序本身的主机关联数量,“主”程序本身的存在主要是为了以正确的顺序和上下文调用各种子例程。在这种情况下,我们可以利用use-association
,选择直接在需要的程序单元内使用
模块实体(例如过程、变量、类型、参数)他们。我们可以进一步限制仅访问那些需要使用 only:
的模块实体。这有助于提高可读性,清楚地指示数据流,而且我发现以后更新代码更直接。您知道,继承、封装等等……但是 Fortran 风格。这实际上非常好。
这是一个适用于我和我用 Fortran 处理过的中等规模项目的示例程序结构。我喜欢将我广泛使用的(静态)参数保存在一个单独的模块(或多个模块,如果根据功能分组)中。我将派生类型和类型绑定(bind)过程保存在另一个单独的模块中。如果它有用,我将某些模块实体设为 private
,这样其他程序单元就无法访问它们。我想就是这样。
module params
implicit none
public !! All items public/accessible by default.
integer, parameter :: dp = kind(0.d0)
integer, parameter :: nrows = 3
real(dp), parameter :: one=1.0_dp, two=2.0_dp
...
end module params
module types
use params, only: dp, nrows
implicit none
public !! Public by default.
private :: dim2
...
integer, parameter :: dim2 = 3
...
type :: A
integer :: id
real(dp), dimension(nrows,dim2) :: data
contains
procedure, pass :: init
end type A
...
contains
subroutine init(self, ...)
...
end subroutine init
...
end module types
module utils
implicit none
private !! Private by default.
public :: workSub1, workSub2, subErr
...
integer,save :: count=0 !! Accessible only to entities in this module.
...
contains
subroutine workSub1(...)
...
end subroutine workSub1
subroutine workSub2(...)
...
end subroutine workSub2
subroutine subErr(...)
...
end subroutine subErr
end module utils
program main
!! An example program structure.
use params, only: dp
implicit none
real(dp) :: xvar, yvar, zvar
integer :: n, i
logical :: rc
call execute_work_subroutines()
contains !! Internal procs inherit all vars declared or USEd.
subroutine execute_work_subroutines()
use types, only: A
type(A) :: DataSet
!! begin
call DataSet%init(i)
do i = 1,n
call workSub1(xvar,yvar,zvar,A,i,rc)
if (rc) call subErr(rc)
call workSub2(A,rc)
if (rc) call subErr(rc)
enddo
end subroutine execute_work_subroutines
end program main
1还有子模块,但我不熟悉它们,不想给出误导性信息。它们对于逻辑上分离大型模块确实很有用。
关于variables - Fortran 中的主机关联与使用关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46202348/
是的,我知道..,这不是想象的...这是一个真正的 Fortran 问题。 以前的版本是指 Fortran 2003、95、90,甚至 77。 我所说的“向后兼容”是指可以轻松运行为 2008 年以前
我有一个程序,它的变量中有一个值。一旦确定了该值,我想调用另一个程序并使用该变量的值来确定在新程序中的位置。有人知道该怎么做吗? 最佳答案 如果您有 Fortran 2008 编译器,您将拥有标准子例
namelist 是一种有用的 fortran 结构,可以从文件中快速初始化变量。 namelist 有一个名称并包含一组具有已知类型的变量。这使得它类似于 type 结构。 通常情况下,给程序或子例
我正在遍历索引,我正在检查我是否不在第一个循环交互和另一个条件中。如果第一个条件是 .False.,我不想评估第二个条件。 do i = 1, n if ( i /= 1 .and. var(
Fortran 2003 具有用于数组连接的方括号语法,Intel fortran 编译器也支持它。我在这里为矩阵连接写了一个简单的代码: program matrix implicit none r
我正在尝试通过重载类型名称来制作自定义数据类型构造函数。但是,在进行调用时,将调用默认构造函数。我不明白我做错了什么。 这是有问题的代码片段。 module test type, pu
我的最终目标是在 Fortran 中有一个通用的映射函数,即一个接受任意类型 A 的数组和一个 A->B 类型的函数的函数,将此函数应用于给定数组的所有元素并返回一个B 类型的数组。我无法用数组实现它
我正在学习 Fortran,在使用格式编写时发现了一些奇怪的东西(我使用的是 Fortran onlinegdb) Program Hello real, dimension(3,2):: array
Fortran 中的INTERFACE 语句是否使其成为正式实现multiple dispatch 的编程语言? ? (我问是因为所链接的维基百科文章在其看似全面的支持相关范式的示例编程语言列表中并未
我可以使用 Fortran 95 编译器编译 Fortran 90 文件吗? Fortran 95 似乎有很多,但 Fortran 90 没有。 最佳答案 这个可以: NAGWare f95 Comp
嗨,我在 Fortran 中对二维离散化问题强加边界条件时遇到了麻烦。我的离散化网格是一个二维正方形,在 x,y 方向上从 -L 到 L。 我想强加这样的边界条件, 在 x=L 的边界线上,指定了函数
Fortran 是否有与 C assert 等效的标准函数/关键字? ? 我找不到 assert我在Fortran2003标准中提到过。我发现了一些如何使用预处理器的方法,但是在这个 answer建议
我有一系列的作业,使用“;”将它们分配给同一个ike。分开statemnts,但我收到此错误: 1.0;磅(1,9) 1个 错误:(1)处无法分类的陈述 在文件LJ.F90:223中 如果每个语句都在
我正在使用 gfortran -std=f2008。我有一个函数,它返回一个包含可分配数组的派生类型。该函数在返回之前调用allocate()。似乎在分配数组的函数返回之后,数组会自动释放一段时间,并
我制作了这个小型测试程序来“证明”在编译之前(或者如果你让它们可分配),你不能在不指定它们的大小的情况下使用向量。我的观点失败了。我期待本地向量“num”会失败。程序在执行程序之前无法知道它的大小。大
出于优化原因,Fortran 强制子例程或函数的虚拟参数不是别名,即它们不指向相同的内存位置。 我想知道相同的约束是否适用于函数的返回值。 换句话说,对于给定的 myfunc 函数: function
我已经在Fortran 90中编写了一个相当大的程序。它已经运行了一段时间了,但是今天我尝试将其提高一个档次并增加问题的大小(这是研究非标准的有限元求解器,如果那样的话)。可以帮助任何人...)现在,
在 C 和 C++ 中,有许多操作会导致未定义的行为,即允许编译器做任何它想做的事情的情况。 Examples包括在释放变量后使用它,释放变量两次和取消引用空指针。 Fortran 是否也有未定义的行
通常我使用fortran进行数值分析,然后使用matlab、R和python进行后期和前期工作。 我发现 matlab、R 和 python 在终端中提供了命令提示符,以便您可以运行脚本以及从命令行立
在 Fortran 中将变量设置为 +Infinity 的最安全方法是什么?目前我正在使用: program test implicit none print *,infinity() con
我是一名优秀的程序员,十分优秀!