Fortran 派生类型可以包含来自不同模块的组件吗?

Can a Fortran derived type have components from different modules?

我正在开发派生类型。它不断增长,并使它所在的模块变得笨拙。有没有办法将模块分解成多个模块,并让派生类型从各个模块获取其组件?

正如@francescalus 指出的那样,您可以使用其他模块的派生类型来 创建新的派生类型。我觉得他的例子有点短,所以我写了一个 我希望这个小例子能让你了解这样的事情是如何发生的 可以工作。也许这个例子比绝对必要的要长,但我 玩得开心。

我的派生类型描述了旅行计划,包括行李和行程。 它带有一个子程序,可以打印给定的旅行计划。

module travel
use Luggage
use Routing
   type tTravel
       type(tItinerary) :: trip
       type(tSuitcase)  :: suitcase
   end type tTravel
contains
   subroutine printTravel(travel)
   implicit none
       type(tTravel), intent(in) :: travel
       print '(a)','    Luggage:'
       call printSuitcase(travel%suitcase)
       print '(a)','    Itinerary:'
       call printItinerary(travel%trip)
   end subroutine printTravel
end module travel

旅行计划的两个组成部分,行李和行程,各有各的 模块。首先,行李模块:

module Luggage
   type tSuitcase
       integer :: socks = 2
       integer :: shirts = 1
       integer :: underwear = 1
       integer :: raincoats = 0
   end type tSuitcase
contains
   subroutine printSuitcase(suitcase)
   implicit none
       type(tSuitcase), intent(in) :: suitcase
       print '(i10,a)', suitcase%socks,'  socks'
       print '(i10,a)', suitcase%shirts,'  shirts'
       print '(i10,a)', suitcase%underwear,'  underwear'
       print '(i10,a)', suitcase%raincoats,'  raincoats'
   end subroutine printSuitcase
end module Luggage

接下来是行程模块:

module Routing
   integer,          parameter :: &
     HOME=1,     MONACO=2,   IBIZA=3,     BIARRITZ=4, &
     nDESTINATIONS=4
   character(len=8), parameter :: destination_names(nDESTINATIONS) = (/ &
     'Home    ', 'Monaco  ', 'Ibiza   ', 'Biarritz' /)
   integer, parameter :: maxTripLen = 100

   type tItinerary
       integer  :: length = 0
       integer  :: destinations(maxTripLen)
   end type tItinerary
contains
   subroutine addDestination(trip,destination)
   implicit none
       type(tItinerary), intent(inout) :: trip
       integer,          intent(in)    :: destination
       if (destination<1 .or. destination>nDESTINATIONS) &
          stop('illegal destination')
       if (trip%length >= maxTripLen) stop('Trip too long')
       trip%length = trip%length + 1
       trip%destinations(trip%length) = destination
   end subroutine AddDestination

   subroutine printItinerary(trip)
   implicit none
       type(tItinerary), intent(in) :: trip
       integer :: i
       if (trip%length==0) then
          print '(a)','        Empty itinerary'
       else
          print '(100(a))','        '//trim(destination_names(trip%destinations(1))), &
             ('-',trim(destination_names(trip%destinations(i))), i=2,trip%length)
       end if
   end subroutine printItinerary
end module Routing

现在我只需要一个主程序:

program nestedModule
use travel
implicit none
   type(tTravel) :: plans

   print '(a)','Before planning anything:'
   call printTravel(plans)

   print *
   print '(a)','Planning a trip ... hold on'
   print *
   call addDestination(plans%trip,HOME)
   call addDestination(plans%trip,IBIZA)
   call addDestination(plans%trip,BIARRITZ)
   call addDestination(plans%trip,HOME)

   print '(a)','Now my plans are:'
   Call printTravel(plans)
end program nestedModule

正如我在第一条评论中指出的那样,在您没有回复的部分,如果您确实需要将组件作为派生类型的实际组件,而不是另一种派生类型的组件,则可以使用类型扩展, 所以如果你想避免进一步将类型构造为树。

请注意,通常使用大型平面字体不是一个好主意,但据我了解,这正是您所要求的,所以这是我的答案...

module mod1

  type part1
    ...many components
  end type
end module

module mod2
  use mod1
  type, extends(part1) :: part2
    ...many other components
  end type
end module

module the_actual_type_mod
  use mod2
  type, extends(part2) :: the_actual_type
    ...many other components
  end type
end module

提到的另一种方式是include。结果不等同,但就您的目的而言几乎等同

module the_actual_type_mod
  use mod2
  type the_type
    include "part1.f90"
    include "part2.f90"
    include "part3.f90"
  end type
end module