Ссылка на функцию, которая возвращает структуру / производный тип

#fortran #fortran90

#fortran #fortran90

Вопрос:

Я борюсь с кратким названием, но это не так сложно. У меня есть функция, которая возвращает структуру (производный тип), и я ищу простой способ ссылаться только на часть структуры при вызове функции (без копирования / указания на другую структуру).

 program main

   real :: xx = 1.
   real :: yy = 2.

   ! works fine but what I want is to be 
   ! able to return %tx and %ts separately

   print *, " tax ", tax(xx,yy)

   ! just guessing at possible syntax here, but neither works

   print *, " tax ", tax%tx(xx,yy)
   print *, " tax ", tax(xx,yy)%tx

contains

function tax(x,y)

   real :: x, y

   type tTax
      real :: tx, ty
   end type tTax

   type(tTax) :: tax

   tax%tx = x * 100.
   tax%ty = y * 100.

end function tax

end program main
  

Я ограничен набором функций f90 / f95, но не стесняйтесь также включать ответы f2003.

И я действительно ищу здесь что-то простое, если оно существует. В противном случае, это просто будет лучше делать как подпрограмму (если альтернативой является сохранение ее как функции, но добавление указателей, интерфейсов и т. Д.).

Я также попытался заставить функцию возвращать 2-мерный массив вместо структуры и столкнулся с той же основной проблемой — это работает, но я могу печатать только весь массив, а не какие-либо разделы массива сами по себе.

Мне было трудно даже угадать синтаксис, поскольку () он используется как для функций, так и для разделов массива в fortran (в отличие от таких языков, как python, которые используются [] для индексации, поэтому вполне естественно смешивать функции и индексы, например, что-то вроде tax(xx,yy)[1,:] ).

Ответ №1:

Вы можете создать пользовательский конструктор, перегрузив имя производного типа данных возвращаемой функцией.

Широкое использование конструкции стандарта Fortran 2003 associate позволяет получить доступ к компонентам определенного типа без копирования или обращения к указателям, подверженным утечке памяти.

Есть ли какая-то особая причина, по которой вы ограничиваете себя Fortran 2003; большая часть Fortran 2008 поддерживается большинством популярных компиляторов.

Следующий код

 module mymod

  ! Explicit typing only
  implicit none

  ! Declare derived data type
  type tTax
     real :: tx, ty
  end type tTax

  ! User-defined constructor
  interface tTax
     module procedure tax
  end interface tTax

contains

  function tax(x, y) result (return_value)
    real, intent (in) :: x, y
    type (tTax)       :: return_value

    return_value%tx = x * 100.0
    return_value%ty = y * 100.0

  end function tax

end module mymod

program main

  use mymod

  ! Explicit typing only
  implicit none

  real       :: xx = 1.0, yy = 2.0
  type(tTax) :: foo

  print *, " tax ", tax(xx,yy)
  print *, " tax ", tTax(xx, yy)

  ! Invoke the user-defined constructor
  foo = tTax(xx, yy)

  ! Fortran 2003's associate construct
  associate( amp;
       tx => foo%tx, amp;
       ty => foo%ty amp;
       )
       print *, " tax ", tx, ty
  end associate

end program main
  

выдает

 gfortran -Wall -o main.exe mymod.f90 main.f90
./main.exe
  tax    100.000000       200.000000    
  tax    100.000000       200.000000    
  tax    100.000000       200.000000 
  

Комментарии:

1. Спасибо, 1. Как я догадался в вопросе, fortran выполняет эту дополнительную работу, так что с практической точки зрения я могу просто использовать подпрограмму, поскольку она немного проще — и на данный момент у меня нет достаточно нового компилятора, чтобы протестировать его в любом случае. 😉 Но это круто, спасибо!

2. Я знаю, что без f2003 я не могу использовать associate() в main, но должен ли модуль сам компилироваться для меня? Мой компилятор f90 жалуется на тип и интерфейс, оба из которых используют имя tTax, но скомпилирует любой из них отдельно (конечно, main в этих случаях не работает). Если бы я мог просто использовать foo%tx в main, а не tx, это было бы достаточным решением с моей точки зрения.

3. @VladimirF или jlok: есть ли какой-нибудь простой ответ на мой комментарий прямо здесь? Или это стоит задать как отдельный вопрос?

4. @JohnE, Вероятно, отдельный вопрос. Это недостаточно ясно из вашего описания. Возможно, старый компилятор, возможно, неправильный код.

Ответ №2:

Проблема не в символах круглых скобок, а в том, разрешено ли вам ссылаться на компонент или элемент выражения или нет.

И в Fortran вам это не разрешено. Вы можете использовать только синтаксис % или индексацию массива () для имен переменных или констант или для ассоциированных имен.

Комментарии:

1. Верно, это было мое рабочее предположение, но я всегда надеюсь на какой-то синтаксический сахар в стиле python, хотя это, похоже, противоречит духу fortran. 😉

2. @JohnE Вот ссылка на Python Fortran Rosetta Stone fortran90.org/src/rosetta.html

3. @jlokimlin да, это хорошо, хотя и интересно, что для моей проблемы он обрабатывает подпрограммы fortran как эквивалент python / numpy! Моя проблема здесь, очевидно, в том, что я пытаюсь заставить функцию fortran работать как функцию python, и, возможно, я просто изо всех сил пытаюсь сделать fortran более похожим на python.