派生型#
変数で前述したように、Fortranには5つの組み込みデータ型があります。 _派生型_は、他の組み込み型と他の派生型をカプセル化できる特別な形式のデータ型です。 CおよびC ++プログラミング言語の_struct_と同等と見なすことができます。
派生型の概要#
基本的な派生型の例を次に示します
type :: t_pair
integer :: i
real :: x
end type
t_pair
型の変数を作成し、そのメンバーにアクセスするための構文は次のとおりです。
! Declare
type(t_pair) :: pair
! Initialize
pair%i = 1
pair%x = 0.5
パーセント記号
%
は、派生型のメンバーにアクセスするために使用されます。
上記のコードスニペットでは、派生型のインスタンスを宣言し、そのメンバーを明示的に初期化しました。派生型コンストラクターを呼び出すことによって、派生型メンバーを初期化することもできます。
派生型コンストラクターを使用した例
pair = t_pair(1, 0.5) ! Initialize with positional arguments
pair = t_pair(i=1, x=0.5) ! Initialize with keyword arguments
pair = t_pair(x=0.5, i=1) ! Keyword arguments can go in any order
デフォルト初期化を使用した例
type :: t_pair
integer :: i = 1
real :: x = 0.5
end type
type(t_pair) :: pair
pair = t_pair() ! pair%i is 1, pair%x is 0.5
pair = t_pair(i=2) ! pair%i is 2, pair%x is 0.5
pair = t_pair(x=2.7) ! pair%i is 1, pair%x is 2.7
派生型の詳細#
すべてのオプションのプロパティを含む派生型の完全な構文を以下に示します
type [,attribute-list] :: name [(parameterized-declaration-list)]
[parameterized-definition-statements]
[private statement or sequence statement]
[member-variables]
contains
[type-bound-procedures]
end type
派生型を宣言するためのオプション#
attribute-list
は以下を指します
public
またはprivate
のいずれかである_アクセス-型_bind(c)
Cプログラミング言語との相互運用性を提供しますextends(
_親_)
。ここで、_親_は、現在の派生型がすべてのメンバーと機能を継承する、以前に宣言された派生型の名前です。abstract
– 高度なプログラミングチュートリアルで説明されているオブジェクト指向機能
属性
bind(c)
またはステートメントsequence
が使用されている場合、派生型は属性extends
を持つことができず、その逆も同様です。
sequence
属性は、以下のメンバーが派生型内で定義されているのと同じ順序でアクセスされる必要があることを宣言するためにのみ使用できます。
sequence
を使用した例
type :: t_pair
sequence
integer :: i
real :: x
end type
! Initialize
type(t_pair) :: pair
pair = t_pair(1, 0.5)
ステートメント
sequence
を使用すると、以下に定義されているデータ型がallocatable
型でもpointer
型でもないことが前提となります。さらに、これらのデータ型がメモリに特定の形式で格納されることを意味するものではありません。つまり、contiguous
属性との関係はありません。
_アクセス-型_属性public
とprivate
は、使用されている場合、以下に宣言されているすべてのメンバー変数に属性が自動的に割り当てられることを宣言します。
属性bind(c)
は、Fortranの派生型とCの構造体の互換性を実現するために使用されます。
bind(c)
を使用した例
module f_to_c
use iso_c_bindings, only: c_int
implicit none
type, bind(c) :: f_type
integer(c_int) :: i
end type
end module f_to_c
次のC構造体型と一致します
struct c_struct {
int i;
};
属性
bind(c)
を持つFortran派生型は、sequence
属性とextends
属性を持つことができません。さらに、Fortranのpointer
型またはallocatable
型を含めることはできません。
parameterized-declaration-list
はオプションの機能です。使用されている場合、パラメータは[parameterized-definition-statements]
の代わりにリストする必要があり、len
パラメータまたはkind
パラメータ、またはその両方である必要があります。
parameterized-declaration-list
と属性public
を使用した派生型の例
module m_matrix
implicit none
private
type, public :: t_matrix(rows, cols, k)
integer, len :: rows, cols
integer, kind :: k = kind(0.0)
real(kind=k), dimension(rows, cols) :: values
end type
end module m_matrix
program test_matrix
use m_matrix
implicit none
type(t_matrix(rows=5, cols=5)) :: m
end program test_matrix
この例では、パラメータ
k
にはすでにデフォルト値kind(0.0)
(単精度浮動小数点数)が割り当てられています。したがって、メインプログラム内の宣言のように、省略できます。
デフォルトでは、派生型とそのメンバーはパブリックです。ただし、この例では、属性
private
がモジュールの先頭で使用されています。したがって、モジュール内のすべては、明示的にpublic
として宣言されない限り、デフォルトでprivate
になります。上記の例で型t_matrix
に属性public
が指定されていない場合、コンパイラはprogram test
内でエラーをスローします。
属性extends
はF2003標準で追加され、オブジェクト指向パラダイム(OOP)の重要な機能、つまり継承を導入します。子タイプが拡張可能な親タイプから派生できるようにすることで、コードの再利用性を可能にします:type, extends(parent) :: child
。ここで、child
はtype :: parent
からすべてのメンバーと機能を継承します。
属性 extends
を使用した例
module m_employee
implicit none
private
public t_date, t_address, t_person, t_employee
! Note another way of using the public attribute:
! gathering all public data types in one place.
type :: t_date
integer :: year, month, day
end type
type :: t_address
character(len=:), allocatable :: city, road_name
integer :: house_number
end type
type, extends(t_address) :: t_person
character(len=:), allocatable :: first_name, last_name, e_mail
end type
type, extends(t_person) :: t_employee
type(t_date) :: hired_date
character(len=:), allocatable :: position
real :: monthly_salary
end type
end module m_employee
program test_employee
use m_employee
implicit none
type(t_employee) :: employee
! Initialization
! t_employee has access to type(t_date) members not because of extends
! but because a type(t_date) was declared within t_employee.
employee%hired_date%year = 2020
employee%hired_date%month = 1
employee%hired_date%day = 20
! t_employee has access to t_person, and inherits its members due to extends.
employee%first_name = 'John'
employee%last_name = 'Doe'
! t_employee has access to t_address, because it inherits from t_person,
! which in return inherits from t_address.
employee%city = 'London'
employee%road_name = 'BigBen'
employee%house_number = 1
! t_employee has access to its defined members.
employee%position = 'Intern'
employee%monthly_salary = 0.0
end program test_employee
派生型のメンバーを宣言するオプション#
[member-variables]
は、すべてのメンバーデータ型の宣言を指します。これらのデータ型は、上記の例ですでに示されているように、任意の組み込みデータ型、および/または他の派生型にすることができます。ただし、メンバー変数には、type [,member-attributes] :: name[attr-dependent-spec][init]
の形式で、独自の広範な構文を使用できます。
type
: 任意の組み込み型または他の派生型
member-attributes
(オプション)
public
またはprivate
アクセス属性protected
アクセス属性allocatable
dimension
の有無にかかわらず、動的配列を指定しますpointer
,codimension
,contiguous
,volatile
,asynchronous
一般的なケースの例
type :: t_example
! 1st case: simple built-in type with access attribute and [init]
integer, private :: i = 0
! private hides it from use outside of the t_example's scope.
! The default initialization [=0] is the [init] part.
! 2nd case: protected
integer, protected :: i
! In contrary to private, protected allows access to i assigned value outside of t_example
! but is not definable, i.e. a value may be assigned to i only within t_example.
! 3rd case: dynamic 1-D array
real, allocatable, dimension(:) :: x
! the same as
real, allocatable :: x(:)
! This parentheses' usage implies dimension(:) and is one of the possible [attr-dependent-spec].
end type
以下の属性:
pointer
、codimension
、contiguous
、volatile
、asynchronous
は、クイックスタート チュートリアルでは扱わない高度な機能です。ただし、読者がこれらの機能が存在することを知り、認識できるように、ここに示します。これらの機能は、今後の 上級プログラミング ミニブックで詳しく説明します。
型結合手続き#
派生型には、それに *結合* された関数またはサブルーチンを含めることができます。これらを *型結合手続き* と呼びます。型結合手続きは、すべてのメンバー変数宣言の後に続く contains
文に従います。
現代のFortranのOOP機能を掘り下げずに、型結合手続きを完全に説明することは不可能です。ここでは、基本的な使用方法を示す簡単な例に焦点を当てます。
基本的な型結合手続きを持つ派生型の例を次に示します
module m_shapes
implicit none
private
public t_square
type :: t_square
real :: side
contains
procedure :: area ! procedure declaration
end type
contains
! Procedure definition
real function area(self) result(res)
class(t_square), intent(in) :: self
res = self%side**2
end function
end module m_shapes
program main
use m_shapes
implicit none
! Variables' declaration
type(t_square) :: sq
real :: x, side
! Variables' initialization
side = 0.5
sq%side = side
x = sq%area()
! self does not appear here, it has been passed implicitly
! Do stuff with x...
end program main
新しい点
self
は、型結合関数内で派生型t_square
のインスタンスを表すために選択した任意の名前です。これにより、メンバーにアクセスし、型結合手続きを呼び出すときに引数として自動的に渡すことができます。area
関数のインターフェースでは、type(t_square)
の代わりにclass(t_square)
を使用しています。これにより、t_square
を拡張する派生型でarea
関数を呼び出すことができます。キーワードclass
は、OOP機能のポリモーフィズムを導入します。
上記の例では、型結合手続き area
は関数として定義されており、x = sq%area()
や print *, sq%area()
などの式でのみ呼び出すことができます。代わりにサブルーチンとして定義すると、独自の call
文から呼び出すことができます
! Change within module
contains
subroutine area(self, x)
class(t_square), intent(in) :: self
real, intent(out) :: x
x = self%side**2
end subroutine
! ...
! Change within main program
call sq%area(x)
! Do stuff with x...
型結合関数の例とは対照的に、ここでは2つの引数があります
class(t_square), intent(in) :: self
– 派生型自体のインスタンスreal, intent(out) :: x
– 計算された面積を格納し、呼び出し元に返すために使用されます