c - 将 Torvalds 的“Good Taste”应用于 Fortran 链表
问题描述
几年前,Linus Torvalds 做了一个 ted 演讲,他展示了一个链表实现,该实现通过使用指向指针的指针来删除无关的 if 测试,他认为这是“好品味”。一个简单的例子如下:
#include <stdio.h>
#include <stdlib.h>
struct list_entry {
int val;
struct list_entry *next;
};
void list_insert(struct list_entry **head, int val)
{
while (*head)
head = &(*head)->next;
*head = calloc(1, sizeof(**head));
(*head)->val = val;
}
int main(int argc, char *argv[])
{
struct list_entry *head = NULL;
list_insert(&head, 0);
list_insert(&head, 1);
printf("Entry 1: %d\n", head->val);
printf("Entry 2: %d\n", head->next->val);
}
list_insert
通过使用递归和 fortran 的引用调用语义,我能够在 fortran 中进行类似的工作:
module list_type
implicit none
type :: list
integer :: val
type(list), pointer :: next => null()
end type list
contains
recursive subroutine list_insert(lst, val)
type(list), pointer, intent(inout) :: lst
integer :: val
!-
if (associated(lst)) then
call list_insert(lst%next, val)
return
else
allocate(lst)
lst%val = val
end if
end subroutine list_insert
end module list_type
program list_test
use list_type
implicit none
type(list), pointer :: head => null()
call list_insert(head, 0)
call list_insert(head, 1)
call list_insert(head, 2)
print *, head%val
print *, head%next%val
print *, head%next%next%val
end program list_test
有没有办法在不诉诸递归的情况下完成这项工作?到目前为止,我所有的尝试都以失败告终。
编辑:这是我的迭代方法不起作用的示例
module list_type
...
type :: list_ptr
type(list), pointer :: p
end type list_ptr
contains
...
subroutine list_insert_iter(lst, val)
type(list), pointer, intent(inout) :: lst
integer :: val
!-
type(list_ptr) :: walker
walker%p => lst
do while (associated(walker%p))
walker%p => lst%next
end do
allocate(walker%p)
walker%p%val = val
end subroutine list_insert_iter
end module list_type
program list_test
use list_type
implicit none
type(list), pointer :: head => null()
call list_insert_iter(head, 0)
if (.not.associated(head)) stop "FAIL"
end program list_test
解决方案
在 Fortran 中处理指针时,通常需要使用中间包装类型。这种包装器类型的语义更接近于 C 指针的语义,而不是纯 Fortran 指针。
举个例子:
module list_type
implicit none
type :: list_ref
type(list), pointer :: ref => null()
end type list_ref
type :: list
integer :: val
type(list_ref) :: next
end type list
contains
subroutine list_insert(lst_arg, val)
type(list_ref), intent(inout), target :: lst_arg
integer, intent(in) :: val
type(list_ref), pointer :: lst
lst => lst_arg
do while (associated(lst%ref))
lst => lst%ref%next
end do
allocate(lst%ref)
lst%ref%val = val
end subroutine list_insert
end module list_type
program list_test
use list_type
implicit none
type(list_ref) :: head
call list_insert(head, 0)
call list_insert(head, 1)
call list_insert(head, 2)
print *, head%ref%val
print *, head%ref%next%ref%val
print *, head%ref%next%ref%next%ref%val
end program list_test
推荐阅读
- for-loop - 在 Xamarin 中使用 for 循环语句更改图像
- node.js - 如果未找到关系“xxx”,则序列化列“id”
- laravel-5 - SQLSTATE[HY000] [1045] 用户 [...] 访问被拒绝(使用密码:YES) Laravel 5.2 on Live Web Server
- r - 将网格放置在 shapefile 中的多边形上,然后找到每个网格正方形的质心
- javascript - 在控制台中看不到 WebdriverIO 日志(webdriver 日志)
- javascript - 未定义从 json 返回
- javascript - 将 MMMM, dd yyyy 日期转换为 UTC 日期
- python - 包中的代理模型django
- sql-server - CONVERSION FAILED WHEN CONVERTING DATA/OR time 从字符串 VBA 到 SQL Server
- elasticsearch - 如何不将完成建议器存储在 Elasticsearch 的索引中