The V Programing Language の基礎部分
初めに
本日?(June 20th)に使用可能になるという事で、Documentationを読んで基礎部分を書きだしたいなと思いました。
https://vlang.io/docs
何か参考にしていただければ嬉しいです。
仕様
安定した実行のために以下のことが仕様として定義されています。
- null無し
- グローバル変数が使えない
- 未定義な変数があってはいけない
- 未定義な関数があってはいけない
- variable shadowingが禁止
- ある狭いスコープのものを作成した際に定義した変数に関して、そこよりも広いスコープのもので定義されている変数と同名のものがある場合に発生する。
- Bounds checking
- 配列の要素にアクセスする際に、配列要素が実際に存在することを確認すること
- 変数やstruct形のイミュータブル性
- ジェネリクス (Cとかにあるやつと変わらないのかな?)
- メソッドのみ変更可能
- 関数はデフォルトで純粋関数である [
mut
というキーワードを用いて、例外を発生]- (戻り値が引数によってのみ決定されるという意味)
Hello World
Cやその類の言語と同じく、main
がエントリーポイントとなります。
しかし、script
のような1つのファイル内で処理が書き終わる場合はfn main()
を省略できます。
すなわち、以下のようなものを実行してもちゃんと動きます。
println('hello world')
コメント
以下の2パターンでなされます。
複数行のコメントをする際、ネストもできるそうです。
// This is a single line comment.
/* This is a multiline comment.
/* It can be nested. */
*/
関数
関数はfn
で定義します。
fn (変数名 型) 戻り値の型 {} の形で定義していきます。
関数はオーバーロードできません。
main()の後に定義した変数であっても、main()の中で呼び出すことができます。
fn main() {
println(add(77, 33))
}
fn add(x int, y int) int {
return x + y
}
複数の引数を持つ場合に、型が等しければまとめて書くことができます。
fn add(x, y int) int {
return x + y
}
変数
変数は := でのみ宣言と初期化が行われます。
Goでいえば、型推論しか変数を宣言できないという事ですね。
ほかの型に変換する場合は、Type(v) と書くことで可能です。
name := 'Bob'
age := 20
large_number := i64(9999999999)
変数の値を変更するには = を使用します。
V での変数はデフォルトでイミュータブルとなっているため、変数の値を変えられるようにするには、mut
をつけて宣言します。
mut age := 20
println(age)
age = 21
基本の型
bool
string
i8 i16 i32 i64
u8 u16 u32 u64
byte // alias for u8
int // alias for i32
rune // alias for i32, represents a Unicode code point
f32 f64
bool
string
i8 i16 i32 i64
u8 u16 u32 u64
byte // alias for u8
int // alias for i32
rune // alias for i32, represents a Unicode code point
f32 f64
CやGoとは違って、intは32ビット整数となることに注意してください。
String型
文字列は読み出し専用のバイトの配列となっており、イミュータブルです。
文字列の中で、変数を呼ぶ場合、$
を用います。
文字列を連結する場合、 +
を用います。
name := 'Bob'
println('Hello, $name!') // `$` is used for string interpolation
println(name.len)
bobby := name + 'by' // + is used to concatenate strings
println(bobby) // ==> "Bobby"
//$ の使い勝手の良さ
age := 20
println('age = ' + age) //string + int なのでcompileされない
println('age = $age') //compaileされる
Array型
配列の型はその最初の要素で決定され、配列のすべての要素は同じ型でなければなりません。
[1, 2, 3] は整数の配列 []int
['a', 'b'] は文字列の配列 []string
<<
は配列の末尾に値を追加する演算子です。(mut でarrayを定義しないと追加できなさそう)
len
フィールドは配列の長さを返します。
val in array
メソッドは配列に val が含まれていれば true
を返します。
nums := [1, 2, 3]
println(nums) // ==> [1, 2, 3]
println(nums[1]) // ==> "2"
mut names := ['John']
names << 'Peter'
names << 'Sam'
println(names.len) // ==> "3"
println('Alex' in names) // ==> "false"
map型
map型であり、keyがstring のものに関してのみ、「変数宣言だけをする」という事ができる。
存在しないkeyを呼び出すと、valueの型の初期値が返されるみたいです。
mut m := map[string]int{}
m['one'] = 1
println(m['one']) // ==> "1"
println(m['bad_key']) // ==> "0"
numbers := {'one': 1, 'two': 2,}
if
書き方は、以下の通りです。
a := 10
b := 20
if a < b {
println('$a < $b')
} else if a > b {
println('$a > $b')
} else {
println('$a == $b')
}
このように、表すこともできます。
num := 777
s := if num % 2 == 0 {
'even'
} else {
'odd'
}
println(s) // ==> "odd"
in
in
は arrayの中に指定した要素が含まれているかをチェックします。
nums := [1, 2, 3]
println(1 in nums) // ==> true
以下の書き方を用いて、ifの条件を簡易化できます。
if parser.token == .plus || parser.token == .minus || parser.token == .div || parser.token == .mult {
...
}
↓↓↓
if parser.token in [.plus, .minus, .div, .mult] {
...
}
forループ
V でのループ構造は for しかありません。
in
の前で変数を1つ定義した場合、array内の要素が代入されていきます。
in
の前で変数を2つ定義した場合、1つ目がindex, 2つ目が要素となります。
numbers := [1, 2, 3, 4, 5]
for num in numbers {
println(num)
}
names := ['Sam', 'Peter']
for i, name in names {
println('$i) $name') // Output: 0) Sam
}
while
のようなものを書きたい場合、以下のように書きます。
mut sum := 0
mut i := 0
for i <= 100 {
sum += i
i++
}
println(sum) // ==> "5050"
for の後に何も書かなければ無限ループになります。
mut num := 0
for {
num++
if num >= 10 {
break
}
}
println(num) // ==> "10"
Switch
Switchも特に変わった内容はありませんでした。
case
で条件を指定し、どれにも当てはまらなければdefault
の中が実行されます。
os := 'windows'
print('V is running on ')
switch os {
case 'darwin':
println('macOS.')
case 'linux':
println('Linux.')
default:
println(os)
}
Structs
Goと全く同じ作りですね。
インスタンスを定義して、後にやるmethodと組み合わせて力を発揮するものです。
struct Point {
x int
y int
}
p := Point{
x: 10
y: 20
}
println(p.x)
構造体はスタック上に確保されます。
ヒープ上に確保する場合は、以下のように&
接頭子を使用してそのポインタを取得します。
pointer := &Point{10, 10}
println(pointer.x)
Access修正子
構造体のフィールドはデフォルトで非公開かつイミュータブルです (構造体自体もイミュータブル)。
しかし、 pub
と mut
を用いることで変更することができます。
struct Foo {
a int // 非公開, イミュータブル (デフォルト)
mut:
b int // 非公開, ミュータブル
c int
pub:
d int // 公開, イミュータブル (読み取りのみ)
pub mut:
e int // 公開, 親モジュールにおいてのみミュータブル
pub mut mut:
f int // 公開, 親モジュールの内側及び外側でミュータブル
}
メソッド
こちらもGoと全く同じですね。
レシーバ(どのstructに使わせるかを決めるもの)の引数リストは fn
とメソッド名の間で指定します。
fn (インスタンス名 struct名) 関数名(変数 型) 戻り値の型 {} という書き方です。
struct User {
age int
}
fn (u User) can_register() bool {
return u.age > 16
}
user := User{age: 10}
println(user.can_register()) // ==> "false"
user2 := User{age: 20}
println(user2.can_register()) // ==> "true"
純粋関数
これは、戻り値が引数によってのみ決定されるという意味です。
mut
を使うことで、メソッドの引数を変更することができます。
struct User {
is_registered bool
}
fn (u mut User) register() {
u.is_registered = true
}
mut user := User{}
println(user.is_registered) // ==> "false"
user.register()
println(user.is_registered) // ==> "true"
メソッドでなく、普通の関数でも同様のことができます。
fn multiply_by_2(arr mut []int) {
for i := 0; i < arr.len; i++ {
arr[i] *= 2
}
}
mut nums := [1, 2, 3]
multiply_by_2(mut nums)
println(nums) // ==> "[2, 4, 6]"
定数
定数は const
で宣言されます。
定数は必ずすべて大文字でなければなりません(変数との差別化)
const (
PI = 3.14
World = '世界'
)
println(PI)
println(World)
Module
Goのpackageと同じです。
モジュール名にしたい名前でディレクトリを作成し、コードを書いた .v ファイルを入れます。
cd ~/code/modules
mkdir mymodule
vim mymodule/mymodule.v
module mymodule
pub fn say_hi() {
println('hello from mymodule!')
}
作成したmoduleは、import
で呼び出します。
module main
import mymodule
fn main() {
mymodule.say_hi()
}
Interfaces
struct Dog {}
struct Cat {}
fn (d Dog) speak() string { return 'woof' }
fn (c Cat) speak() string { return 'meow' }
interface Speaker {
speak() string
}
fn perform(s Speaker) { println(s.speak()) }
fn main() {
dog := Dog{}
cat := Cat{}
perform(dog) // ==> "woof"
perform(cat) // ==> "meow"
}
Enums
enum Color {
red green blue
}
mut color := Color.red
color = .green // `Color.green` とする必要がない
println(color) // ==> "1"
Option/Result types と error制御
struct Dog {}
struct Cat {}
fn (d Dog) speak() string { return 'woof' }
fn (c Cat) speak() string { return 'meow' }
interface Speaker {
speak() string
}
fn perform(s Speaker) { println(s.speak()) }
fn main() {
dog := Dog{}
cat := Cat{}
perform(dog) // ==> "woof"
perform(cat) // ==> "meow"
}
enum Color {
red green blue
}
mut color := Color.red
color = .green // `Color.green` とする必要がない
println(color) // ==> "1"
Option/Result types と error制御
戻り値の型に ?
を加えて、何かがおかしいときにエラーを返します。
struct User {
id int
name string
}
struct Repo {
users []User
}
fn new_repo() Repo {
return Repo {users: [User{1, 'Andrew'}, User {2, 'Bob'}, User {10, 'Charles'}]}
}
fn (r Repo) find_user_by_id(id int) ?User {
for user in r.users {
if user.id == id {
return user
}
}
return error('User $id not found')
}
fn main() {
repo := new_repo()
user := repo.find_user_by_id(10) or { return }
println(user.id) // ==> "10"
println(user.name) // ==> 'Charles'
}
ジェネリクス
struct Repo⟨T⟩ {
db DB
}
fn new_repo⟨T⟩(db DB) Repo⟨T⟩ {
return Repo⟨T⟩{db: db}
}
// This is a generic function. V will generate it for every type it's used with.
fn (r Repo⟨T⟩) find_by_id(id int) ?T {
table_name := T.name // in this example getting the name of the type gives us the table name
return r.db.query_one⟨T⟩('select * from $table_name where id = ?', id)
}
db := new_db()
users_repo := new_repo⟨User⟩(db)
posts_repo := new_repo⟨Post⟩(db)
user := users_repo.find_by_id(1)?
post := posts_repo.find_by_id(1)?
並列処理
struct Repo⟨T⟩ {
db DB
}
fn new_repo⟨T⟩(db DB) Repo⟨T⟩ {
return Repo⟨T⟩{db: db}
}
// This is a generic function. V will generate it for every type it's used with.
fn (r Repo⟨T⟩) find_by_id(id int) ?T {
table_name := T.name // in this example getting the name of the type gives us the table name
return r.db.query_one⟨T⟩('select * from $table_name where id = ?', id)
}
db := new_db()
users_repo := new_repo⟨User⟩(db)
posts_repo := new_repo⟨Post⟩(db)
user := users_repo.find_by_id(1)?
post := posts_repo.find_by_id(1)?
foo()
を並列実行するには、go foo()
と呼ぶだけということで、goroutineが実装されるのでしょうか。
Author And Source
この問題について(The V Programing Language の基礎部分), 我々は、より多くの情報をここで見つけました https://qiita.com/ryojsb/items/f5270be0b579bd12208f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .