我试图创建一个表示正数的抽象数据类型:
package m
type positiveNum int
func MakePositiveNum(i int) positiveNum {
if i < 1 { panic("non positive number") }
return positiveNum(i)
}
// some function that expects a positive number
func UsePositiveNum(s positiveNum) {}
以下是一些示例用法:
package main
import "m"
func main() {
pn := m.MakePositiveNum(123)
//i := 1; m.UsePositiveNum(i) // fails as expected because
// int is passed instead of positiveNum
//useInt(pn) // fails because trying to pass positiveNum instead of int
//pn = m.positiveNum(0) // fails as expected because the type is private
m.UsePositiveNum(pn)
}
func UseInt(int) {}
如果您将m.UsePositiveNum(pn)
替换为m.UsePositiveNum(0)
,它仍会编译,绕过正数量的类型检查。为什么呢?
答案 0 :(得分:2)
这里发生的事情是0
是untyped constant。这些常量由this rule about assignability:
值
x
可分配给T
类型的变量(&#34;x
可分配给T
&#34;)在任何这些情况下:
- ...
x
是一个无类型常量,可由类型T
的值表示。
由于positiveNum
的基础类型为int
,可以代表0
,因此转换无错误。
@ peterSO的答案提供了一种避免这种隐式转换的方法,因为没有从整数常量到结构的隐式转换。请注意,它无法防止恶意用户创建positive.Positive{0}
之类的值,但这通常不是问题。
答案 1 :(得分:1)
当然是编译。没有任何东西可以阻止类型positiveNum
的值为零或更小。您唯一的运行时检查位于MakePositiveNum
,当您执行以下操作时,您永远不会调用它:
m.UsePositiveNum(0)
接收类型为positiveNum
的值的每个函数/方法都必须进行验证,如果您想确定,则不仅MakePositiveNum
。否则,您必须假设开发人员将始终使用MakePositiveNum
来创建值。
您可以使用image.Rectangle
在标准库中找到类似的内容。它的许多方法都假设Min.X <= Max.X和Min.Y&lt; = Max.Y,但没有实际验证,只保证:
矩形的方法总是为格式良好的输入返回格式良好的输出。
答案 2 :(得分:1)
你可能正在寻找这样的东西:
ADT:
package positive
type Positive struct{ i uint64 }
func New(i int) Positive {
if i < 1 {
panic("not a positive number")
}
return Positive{i: uint64(i)}
}
func Function(p Positive) Positive { return p }
func (p Positive) Method() Positive { return p }
func (p Positive) Integer() uint64 { return p.i }
用法:
package main
import "positive"
func main() {
pn := positive.New(123)
i := 1; positive.Function(i) // fails
UseInt(pn) // fails
pn = positive.Positive(0) // fails
positive.Function(pn)
positive.Function(0) // fails
}
func UseInt(int) {}