栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

创建一个常量类型并限制类型的值

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

创建一个常量类型并限制类型的值

缺陷

提议的解决方案以您想要的方式并不安全。可以使用无类型的整数常量来创建新值,

unary
该新值的
int
值不同于
1
-1
。请参阅以下示例:

p := unary.Positivefmt.Printf("%v %dn", p, p)p = 3fmt.Printf("%v %dn", p, p)

输出将是:

+ 1- 3

我们可以更改其

p
值来存储显然不等于或不等于的
int
值。这是可能的,因为规格:可分配性:
3``Positive``Negative

在以下任何一种情况下,值

x
都可以 分配 给类型的变量
T
(“
x
可以分配给
T
”):

  • x
    是可由type值表示的无类型常量
    T


3
是一个无类型的常量,可以用
unary
具有基础type 的type值表示
int

在Go中,由于上面提到的原因,您不能拥有“安全”常量,而“局外人”软件包无法为其创建新值。因为如果要在包中声明 常量
,则只能使用具有“未类型化”版本的表达式,其他表达式也可以在赋值中使用这些表达式(就像我们的示例一样)。

未导出的结构

如果要实现“安全”部分,则可以使用unexported

struct
,但是不能在常量声明中使用它们。

例:

type unary struct {    val int}var (    Positive = unary{1}    Negative = unary{-1})func (u unary) String() string {    if u == Positive {        return "+"    }    return "-"}func (u unary) CalExpr() int {    return u.val}

尝试更改其值:

p := unary.Positivep.val = 3 // Error: p.val undefined (cannot refer to unexported field or method val)p = unary.unary{3} // Error: cannot refer to unexported name unary.unary// Also error: implicit assignment of unexported field 'val' in unary.unary literal

请注意,由于我们现在使用

struct
,我们可以通过将
string
值的表示形式添加到来进一步简化代码
struct

type unary struct {    val int    str string}var (    Positive = unary{1, "+"}    Negative = unary{-1, "-"})func (u unary) String() string { return u.str }func (u unary) CalExpr() int { return u.val }

请注意,此解决方案仍然存在“缺陷”:它使用导出的全局变量,其值可以由其他程序包更改。确实其他软件包不能创建和分配
值,但是它们可以使用现有值来创建和分配 值,例如:

unary.Positive = unary.Negative

如果要保护自己免受滥用,还必须使此类全局变量不导出。然后,当然,您必须创建导出的函数以公开这些值,例如:

var (    positive = unary{1}    negative = unary{-1})func Positive() unary { return positive }func Negative() unary { return negative }

然后获取/使用这些值:

p := unary.Positive()

接口

如果打算为“常量”使用接口类型,则必须小心。卡夫·沙赫巴赞的回答中可以看到一个例子。未导出的方法用于防止其他人实现该接口,给您一种幻觉,即其他人确实无法实现该接口:

type Unary interface {    fmt.Stringer    CalExpr() int    disabler() // implementing this interface outside this package is disabled}var (    Positive Unary = unary(1)  // visible outside of the package unary    Negative Unary = unary(-1) // visible outside of the package unary)type unary int // not visible outside of the package unaryfunc (u unary) disabler() {}func (u unary) String() string {  }func (u unary) CalExpr() int {  }

但是事实并非如此。有了一个肮脏的把戏,就可以绕开它。

Unary
可以嵌入导出的类型,并且可以使用现有值来实现接口(以及未导出的方法),并且我们可以添加导出方法的自己的实现,执行/返回我们想要的任何操作。

看起来是这样的:

type MyUn struct {    unary.Unary}func (m MyUn) String() string { return "/" }func (m MyUn) CalExpr() int { return 3 }

测试它:

p := unary.Positivefmt.Printf("%v %dn", p, p)p = MyUn{p}fmt.Printf("%v %dn", p, p.CalExpr())

输出:

+ 1/ 3

特殊情况

正如沃尔克在评论中所提到的,在特殊情况下,您可以使用

type unary boolconst (    Positive unary = true    Negative unary = false)

由于类型

bool
具有两个可能的值:
true
false
,因此我们已经使用了所有值。因此,没有其他可以“利用”的值来创建我们常量类型的其他值。

但是要知道,只有在常量的数量等于类型的可能值的数量时才能使用此方法,因此该技术的可用性非常有限。

另外请记住,当

unary
期望使用的类型,并且有人不小心传递了诸如
true
或的无类型常量时,这不能防止这种滥用
false



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/378366.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号