自定义类型的重载

函数重载

当定义的函数很多的时候,函数名会非常复杂,有时候我们希望可以简化,这时候,使用重载是一个选择。例如对于vector类型,我们希望它也可以通过传入一个数组来初始化。使用generic关键字就可以对函数进行重载

module vector_mod
  implicit none
  type vector_t
    real,allocatable::x(:)
  contains
    generic::init=>vector_init,vector_init_array
    procedure,pass:: vector_init,vector_init_array
  end type vector_t
contains
  subroutine vector_init(this,n)
    class(vector_t),intent(inout)::this
    integer,intent(in)::n
    allocate(this%x(n))
  end subroutine vector_init

  subroutine vector_init_array(this,a)
    class(vector_t),intent(inout)::this
    real,intent(in)::a(:)
    allocate(this%x,source=a)
  end subroutine vector_init_array
end module vector_mod

program main
  use vector_mod
  implicit none
  type(vector_t)::v
  type(vector_t)::va
  call v%init(10)
  call va%init([real::1,2,3,4])
end program main

此时使用两种方式均可以对其进行初始化。

运算符重载

有时候,我们也希望对内置的运算符进行重载,用来提高代码的一致性。例如我们有一个分数类型,它有+-*/**的操作,但是如果使用过程绑定的函数则显得代码过于臃肿。此时就可以使用运算符重载

module frac_mod
    implicit none
    type frac
        integer(8)::num!numerator
        integer(8)::den!denominator
    contains
        generic::operator(.reduce.)=>cancelling !也可以使用自定义运算符
        generic::operator(+)=>add,add_frac_num,add_num_frac
        !generic::operator(-)=>sub
        !generic::operator(*)=>mult
        !generic::operator(/)=>div
        !generic::operator(**)=>pow
        !
        procedure,pass      ::add,add_frac_num
        procedure,pass(this)::add_num_frac
        procedure,pass      ::cancelling
        !procedure,pass::sub
        !procedure,pass::mult
        !procedure,pass::divi
    end type
contains
    elemental function cancelling(this)result(z)
        class(frac),intent(in)::this
        type(frac)           ::z
        ! do something
    end function cancelling

    type(frac) elemental function add(this,y)result(z)
        class(frac),intent(in)::this,y
        z%num=this%num*y%den+y%num*this%den
        z%den=this%den*y%den
    end function add

    type(frac) elemental function add_frac_num(this,m)result(z)
        class(frac),intent(in)::this
        integer,intent(in)    ::m
        z%num=this%num+this%den * m
        z%den=this%den
    end function add_frac_num

    type(frac) elemental function add_num_frac(m,this)result(z)
        class(frac),intent(in)::this
        integer,intent(in)    ::m
        z%num=this%num+this%den * m
        z%den=this%den
    end function add_num_frac
end module frac_mod

program main
  use frac_mod
  implicit none
  type(frac)::x,y,z,w(2)
  x=frac(1,2)
  y=frac(2,3)
  w=[frac(1,4),frac(1,3)] !自定义类型数组初始化
  z=x+y
  write(*,*)z
  z=x+1
  write(*,*)z
  z=2+y
  write(*,*)z
  write(*,*)w+2 !也支持数组
end program main
  • 除此之外,也可以对比较运算符进行重载,注意比较运算符中运算符和其对应的旧形式属于同一个函数,不能重载为不同的功能。

赋值运算符的重载

赋值的运算符具有特有的形式assignment(=)

module string_mod
  implicit none
  type string
    character(:),allocatable::str
  contains
    generic::assignment(=)=>equal
    procedure,pass::equal
  end type string
contains
  subroutine equal(this,s)
    class(string),intent(inout)::this
    character(len=*),intent(in)::s
    this%str=s
  end subroutine equal
end module string_mod

program main
  use string_mod
  implicit none
  type(string)::s
  s="123"
  !内置构造函数形式 
  s=string("456")
end program main 

习题

  • 请你尝试补充完所有的运算符
  • 尝试加入gcd对分数进行约分,补充.reduce.函数
  • (附加题)完成分数类,并使用高斯消元法求解希尔伯特矩阵的行列式和逆矩阵