Я не думаю, что создание типа оправдано в такой ситуации: я бы просто @assert
подтвердил, что условие проверено в начале функции (ей). (Как ни странно, проверка того, является ли число четным, является примером, выбранным в документации для иллюстрации эффекта @assert
)
Например:
julia> function grof(x::Int)
@assert iseven(x) "Stupid programmer!"
println("good")
end
grof (generic function with 1 method)
julia> grof(2)
good
julia> grof(3)
ERROR: AssertionError: Stupid programmer!
Stacktrace:
[1] grof(::Int64) at ./REPL[5]:2
[2] top-level scope at REPL[7]:1
РЕДАКТИРОВАТЬ: Если вы действительно хотите создать тип, обеспечивающий такое ограничение, это возможно. Способ сделать это -
- создать тип (возможно, подтипить один из
Number
абстрактных типов; возможно, Signed
) - определить внутренний конструктор, гарантирующий, что такой тип не может содержать нечетное значение
Очень простой пример, на котором можно основываться, будет выглядеть следующим образом:
# A wrapper around an even integer value
struct EvenInt
val :: Int
# inner constructor
function EvenInt(val)
@assert iseven(val)
new(val)
end
end
# Accessor to the value of an EvenInt
val(x::EvenInt) = x.val
# A method working only on even numbers
grof(x::EvenInt) = println("good: $(val(x)) is even")
Вы бы использовали это так:
julia> x = EvenInt(42)
EvenInt(42)
julia> grof(x)
good: 42 is even
julia> y = EvenInt(1)
ERROR: AssertionError: iseven(val)
Stacktrace:
[1] EvenInt(::Int64) at ./REPL[1]:5
[2] top-level scope at REPL[6]:1
но учтите, что вы ничего не можете сделать на EvenInt
с: вам нужно либо развернуть их (в данном случае используя val()
), либо определить операции над ними (задача, которая может быть очень упрощается, если вы сделаете EvenInt
подтипом одного из типов абстрактных чисел и будете следовать соответствующему интерфейсу).