LoginSignup
0
0

More than 1 year has passed since last update.

go にも decltype が欲しいよ、と思った話。

Last updated at Posted at 2022-12-24

これは何?

go を書いていて、初めて decltype ほしいよと真剣に思ったので、その記録。

decltype ってのは、C++ にある言語要素で、式からその式の型を得る機能。

c++
using usec_t = decltype (timeval{}.tv_usec);

のようにすると、usec_t を 構造体 timeval のメンバ tv_usec の型にすることができる。便利。

そして。

にも参加しています。

ほしいよと思った経緯。

unix.Timeval を使いたい

go で unix.Timeval を使おうと思った。
まあ使おうと思った時点で負けという気もちょっとするけど、まあ使おうと思った。

float64 の値をゴニョゴニョして作った値で unix.Timeval を初期化したい。

unix.Timeval は、 SecUsec というメンバを持っていてこれに値を入れたい。

ターゲット

しかしターゲット環境は

  • linux 386
  • linux amd64
  • darwin amd64

の三種(だということにする)。

それぞれの環境での Sec Usec の型は下表のとおり。

型 \ 環境 linux 386 linux amd64 darwin amd64
Sec int32 int64 int64
Usec int32 int64 int32

C/C++ と違って型が違う変数への代入は全面禁止。もとの値の intervalfloat64

書きたかったコード

go
type SecType = なんか
type UsecType = なんか

t := unix.Timeval{
	Sec:  SecType(math.Floor(interval)),
	Usec: UsecType((interval - math.Floor(interval)) * 1e6),
}

こうしたい。
こうしたいんだが、「なんか」の場所に typeOf(unix.Timeval{}.Sec) などと書くことはできない。

実際にできること

仕方ないので

  • unsafe.Sizeof などを駆使してなんとかする
  • 条件コンパイルで UsecTypeUsecType を適宜定義する
  • go generate でなんとかできるのかも。よく知らない。

の三択から選ぶことになるんだと思う。他にもあるかな。
私は条件コンパイルを選んだ。
こういうことに頭を使わせないでほしいと思う。

go1.18 以降なら

今なら、 Generics が使えるので

go1.18以降
type SecConstraint interface {
	int32 | int64
}

type UsecConstraint interface {
	int32 | int64
}

func hoge[S SecConstraint, U UsecConstraint](s *S, u *U, interval float64) {
	*s = S(math.Floor(interval))
	*u = U((interval - math.Floor(interval)) * 1e6)
}

としておけば

go1.18以降
t := unix.Timeval{}
hoge(&t.Sec, &t.Usec, interval)

と書ける。

しかしトリッキーな感じは否めない。
やっぱり前述の「書きたかったコード」のようにしたいよなぁと思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0