为了账号安全,请及时绑定邮箱和手机立即绑定

如何将函数参数静态限制为值的子集

如何将函数参数静态限制为值的子集

Go
万千封印 2021-07-09 19:02:04
如何将函数参数静态约束为所需类型的值的子集?这组值将是在包中定义的一个小集合。如果它是编译时检查而不是运行时检查会很好。我已经能够弄清楚的唯一方法是这样的:package foo// subset of valuesconst A = foo_val(0)const B = foo_val(1)const C = foo_val(2)// local interface used for constrainttype foo_iface interface {    get_foo() foo_val}// type that implements the foo_iface interfacetype foo_val intfunc (self foo_val) get_foo() foo_val {    return self}// function that requires A, B or Cfunc Bar(val foo_iface) {    // do something with `val` knowing it must be A, B or C}因此,现在包的用户无法替换任何其他值来代替A,B或C。package mainimport "foo"func main() {    foo.Bar(foo.A) // OK    foo.Bar(4)     // compile-time error}但这似乎需要很多代码来完成这个看似简单的任务。我有一种感觉,我把事情搞得太复杂了,错过了语言中的一些功能。该语言是否具有某些功能可以以简洁的语法完成相同的事情?
查看完整描述

2 回答

?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

Go做不到这个(我不认为,我不认为几个月让我有经验)


ADA 可以,而 C++ 有时可以但不干净(constexpr 和 static_assert)。


但真正的问题/要点在这里,为什么重要?我使用 Go 和 GCC 作为编译器,GCC 非常聪明,尤其是使用 LTO,恒定传播是最容易应用的优化之一,它不会打扰检查(你是(无论如何我们在 C 中称之为)静态检查初始化 AB 和 C,GCC 对此进行了优化(如果它有函数的定义,则使用 LTO))


现在这有点离题了,所以我将停止使用那个混搭的 blob,但是除非您的程序受 CPU 限制,否则测试一个值的合理性是好的,不要担心。


总是写更容易阅读的东西,你会感谢你以后所做的


因此,请执行您的运行时检查,如果编译器有足够的信息来处理它,如果它可以推断(证明)它们不会抛出,它就不会费心去做,像这样的常量值它会很容易地发现它。


附录


很难进行编译时检查,例如,c++ 中的 constexpr 非常有限(它涉及的所有内容也必须是 constexpr 等)——它不能很好地与普通代码一起使用。


假设一个值来自用户输入?该检查必须在运行时进行,如果您编写了两组约束(但是这行得通),一组用于编译,一组用于运行,那将是愚蠢的(并且违反 DRY)。


我们能做的最好的事情就是让编译器非常聪明,而 GCC 就是这样。我相信其他人也很好(“除了 MS,我从来没有听到过对它的赞美,但作者很聪明,因为他们一开始就编写了一个 C++ 解析器!)


查看完整回答
反对 回复 2021-07-12
?
眼眸繁星

TA贡献1873条经验 获得超9个赞

一种可能适合您需要的略有不同的方法是使函数成为该类型的方法并导出有效值集,但不是构造新值的方法。


例如:


package foo


import (

    "fmt"

)


// subset of values

const A = fooVal(0)

const B = fooVal(1)

const C = fooVal(2)


// type that implements the foo_iface interface

type fooVal int


// function that requires A, B or C

func (val fooVal) Bar() {

    fmt.Println(val)

}

使用人:


package main


import "test/foo"


func main() {

    foo.A.Bar() // OK, prints 0

    foo.B.Bar() // OK, prints 1

    foo.C.Bar() // OK, prints 2

    foo.4.Bar()     // syntax error: unexpected literal .4

    E := foo.fooVal(5) // cannot refer to unexported name foo.fooVal

}


查看完整回答
反对 回复 2021-07-12
  • 2 回答
  • 0 关注
  • 219 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信