#tuples #nim-lang
#кортежи #nim-lang
Вопрос:
Я пытаюсь создать proc, который возвращает пользовательский кортеж, содержащий один элемент, который является типом proc, т.Е.
type
CustomTuple = tuple
foo: proc(input: int): int
proc createCustomTuple(): CustomTuple =
(foo: proc(input: int): int = 10)
Однако, когда я компилирую это, я получаю следующую ошибку (я компилирую с Nim версии 1.2.6 в Windows).
Ошибка: несоответствие типов: получен <кортеж[foo: proc (input: int): int{.noSideEffect, gcsafe, locks: 0.}]> но ожидаемый ‘CustomTuple = кортеж [foo: proc (input: int): int{.closure.}]’
Итак, компилятор думает, что я возвращаю обычный кортеж, а не CustomTuple
но я понятия не имею, как это изменить, чтобы заставить его работать. Документация для кортежей в руководстве по Nim показывает, что пользовательские кортежи создаются так, как я это делаю, и я не смог найти никаких примеров возврата пользовательского кортежа из proc.
Если я изменю свое CustomTuple
определение так, чтобы оно содержало типы, которые не являются proc, то оно успешно компилируется, поэтому кажется, что это связано с тем, что мой пользовательский кортеж, содержащий proc, вызывает сбой компиляции.
Кто-нибудь может объяснить, почему приведенный выше код не компилируется?
Ответ №1:
Я думаю, что причина, по которой мой исходный код не работает, заключается в том, что Nim не может автоматически преобразовать proc в замыкание при его добавлении в кортеж. На форумах Nim есть некоторые обсуждения по этому поводу.
Поскольку proc не преобразуется в замыкание, компилятор не может определить, что возвращаемый кортеж является CustomTuple
, поскольку типы не совпадают, что объясняет сообщение об ошибке.
Поэтому при упаковке proc в кортеж вам необходимо явно преобразовать его в замыкание. Это может быть сделано путем явного приведения процесса следующим образом:
type
CustomTuple = tuple
foo: proc(input: int): int
proc createCustomTuple(): CustomTuple =
(foo: (proc(input:int):int)(proc(input: int): int = 10))
или путем добавления {.closure.}
такой прагмы (которая, я думаю, намного чище).
type
CustomTuple = tuple
foo: proc(input: int): int
proc createCustomTuple(): CustomTuple =
(foo: proc(input: int): int {.closure.} = 10)
Если вы не хотите выполнять ни одно из этих действий, вы можете присвоить proc foo
свойству неявной result
переменной в соответствии с ответом Салевски.
Это также объясняет, почему оригинальное решение Салевски о присвоении proc foo
свойству неявной result
переменной сработало; в этом случае компилятор может автоматически преобразовать proc в замыкание.
Ответ №2:
type
CustomObject = object
foo: proc(input: int): int
proc createCustomObject(): CustomObject =
#(foo: proc(input: int): int = 10)
#result.foo = proc(input: int): int = 10
CustomObject(foo: proc(input: int): int = input * 2)
var x = createCustomObject()
echo x.foo(2)
Комментарии:
1. 1 Это обеспечивает решение, которое функционально эквивалентно, но на самом деле не объясняет, почему мой исходный код не компилируется, что мне действительно интересно понять.
2. Обратите внимание, что это решение также не требует от нас говорить
result.foo = ...
, что просто подчеркивает, что при использовании пользовательских кортежей происходит что-то другое.