Go で競技プログラミングを行うためのツールです。
main
関数から使用されているコードのみを抽出し、gofmt
をかけた上で、1 つのファイルとして出力します。
go install github.com/murosan/gollect/cmd/gollect@latest
実行時に AST をパースしている関係で、インストール時の Go のバージョンに依存しています。
Go のバージョンを変更したときは、再インストールしてください。
以下のような Min
,Max
関数を lib
パッケージに実装したとします。
package lib
import "golang.org/x/exp/constraints"
func Min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
続いて、main
パッケージを実装します。
以下は 2 つの数値を読み取って大きい方を出力するコードです。
package main
import (
"fmt"
"github.com/your-name/repo-name/lib"
)
func main() {
var a, b int
fmt.Scan(&a, &b)
max := lib.Max(a, b)
fmt.Println(max)
}
gollect を実行します。
$ gollect -in ./main.go
以下のように、そのまま提出できるコードが出力されます。
package main
import (
"fmt"
"golang.org/x/exp/constraints"
)
func main() {
var a, b int
fmt.Scan(&a, &b)
max := Max(a, b)
fmt.Println(max)
}
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}
自作パッケージ(github.com/your-name/repo-name/lib
)のインポート文や、使用されていないMin
関数は出力されません。
golang.org/x/exp/constraints
パッケージはデフォルトで残すように設定されています。
設定内容は後述します。
設定ファイルを YAML で書くことができます。
設定ファイルを cli で指定するには-config
オプションで指定します。
$ gollect -config config.yml
inputFile: main.go
outputPaths:
- stdout
thirdPartyPackagePathPrefixes:
- golang.org/x/exp
- github.com/emirpasic/gods
- github.com/liyue201/gostl
- gonum.org/v1/gonum
指定すると、デフォルトの設定を上書きできます。
オプションが省略された場合、デフォルトの設定が使用されます。
key | type | description | default |
---|---|---|---|
inputFile | string | main 関数があるファイルを指定します。main パッケージファイルが複数ある場合、globで全て指定する必要があります。 |
main.go |
example:
inputFile: main.go
inputFile: ./*.go
key | type | description | default |
---|---|---|---|
outputPaths | []string | 出力先を指定します。 設定可能な値: stdout ,clipboard ,ファイルパス |
stdout |
example:
outputPaths:
- stdout
- clipboard
- out/main.go
key | type | description | default |
---|---|---|---|
thirdPartyPackagePathPrefixes | []string | ジャッジシステム上で使用できるパッケージのプレフィックスを指定します。 ここで指定されたパッケージはインポート文などが削除されずに残ります。 |
golang.org/x/exp github.com/emirpasic/gods github.com/liyue201/gostl gonum.org/v1/gonum |
example:
thirdPartyPackagePathPrefixes:
- golang.org/x/exp
- github.com/emirpasic/gods
thirdPartyPackagePathPrefixes: []
最終的に main 関数から使用されていない宣言は無視されます。
メソッドも例外ではありません。
// input
package main
import "sort"
type S[T ~int | ~string] []T
func (s S[T]) Len() int { return len(s) }
func (s S[T]) Less(i, j int) bool { return s[i] < s[j] }
func (s S[T]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func main() {
var s S[int]
sort.Sort(&s)
}
// output
// !! compile error !!
package main
import "sort"
type S[T ~int | ~string] []T
func main() {
var s S[int]
sort.Sort(&s)
}
Len
、Less
、Swap
メソッドは main
関数から直接呼び出されないため削除されていますが、残さなければコードが機能しません。
これらを残すには、2 つの方法があります。
// input
package main
import "sort"
type S[T ~int | ~string] struct {
sort.Interface
data []T
}
func (s *S[T]) Len() int { return len(s.data) }
func (s *S[T]) Less(i, j int) bool { return s.data[i] < s.data[j] }
func (s *S[T]) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }
func (*S[T]) Unused() {} // will be removed
func main() {
var s S[int]
sort.Sort(&s)
}
// output
package main
import "sort"
type S[T ~int | ~string] struct {
sort.Interface
data []T
}
func (s *S[T]) Len() int { return len(s.data) }
func (s *S[T]) Less(i, j int) bool { return s.data[i] < s.data[j] }
func (s *S[T]) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }
func main() {
var s S[int]
sort.Sort(&s)
}
コメントに // gollect: keep methods
を書くと、全てのメソッドを残します。
// input
package main
import "sort"
// gollect: keep methods
type S[T ~int | ~string] []T
func (s S[T]) Len() int { return len(s) }
func (s S[T]) Less(i, j int) bool { return s[i] < s[j] }
func (s S[T]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (S[T]) Unused() {} // will be left
func main() {
var s S[int]
sort.Sort(&s)
}
// output
package main
import "sort"
type S[T ~int | ~string] []T
func (s S[T]) Len() int { return len(s) }
func (s S[T]) Less(i, j int) bool { return s[i] < s[j] }
func (s S[T]) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (S[T]) Unused() {} // will be left
func main() {
var s S[int]
sort.Sort(&s)
}
import "C" // cannot use
package main
import . "fmt" // cannot use
func main() { Println() }
package pkg
func init() {}
package main
import _ "github.com/owner/repo/pkg" // cannot use
func main() {}