├── .gitignore
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── LICENSE
├── README.md
├── learnv_jp.v
└── learnv.v
/.gitignore:
--------------------------------------------------------------------------------
1 | learnv
2 | learnv_jp
3 | *.c
4 | *.txt
5 | *.exe
6 | learnv-gcc
7 | learnv-tcc
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 The V Programming Language Community
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.LICENSE
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Learn X in Y Minutes, X = [V]
2 | 1. [Overview](#Overview)
3 | 2. [Contributing](#Contributing)
4 | 3. [License](#License)
5 |
6 |
7 | ## Overview
8 | This is a series of short examples designed to demonstrate the syntax, data types, and conventions of the programming language [V]. This is a brief introduction that should allow one to delve into the more intricate topics to follow. After you've finished this tutorial, please feel free to visit the official [V Documentation] or check out other examples from the [V Community].
9 |
10 | *Tested for V 0.2*
11 |
12 | ## Contributing
13 | Thanks for your interest in helping with the project. Feel free to report issues and make pull requests. Keep in mind that the goal of this project is introduce the main concepts of the [V] Programming Language. It is not meant to be a comprehensive guide that covers all of V's features and ideas.
14 |
15 |
16 | ## License
17 | Currently, this project will be licensed under the MIT license. You can review the terms of license in the [LICENSE](LICENSE) file.
18 |
19 | [V]: https://vlang.io
20 | [V Documentation]: https://vlang.io/docs
21 | [V Community]: https://github.com/v-community
22 |
--------------------------------------------------------------------------------
/learnv_jp.v:
--------------------------------------------------------------------------------
1 | /*
2 | Translators:
3 | 1. https://github.com/kmry
4 | Other Translations filled in by Google Translate
5 | Vの基本的なデータ型:
6 | bool - true/false
7 | string - 'hello' *utf-8 encoded*
8 | i8 i16 int i64 i128[WIP] - signed integers of 8, 16, 32, 64, and 128 bits
9 | byte u16 u32 u64 u128[WIP] - unsigned integers of 8, 16, 32, 64, and 128 bits
10 | f32 f64 - floating point numbers of 32 and 64 bits
11 | rune - unicode code point (ascii charのUnicode版)
12 | byteptr
13 | voidptr
14 | 開発者メモ:CやGoとは異なり、intは常に32ビットです。
15 | */
16 | // 標準ライブラリ並びにvpmを使用してインストールされたすべてのパッケージは、プログラムの開始時にロードされます。
17 | import math
18 |
19 | // don't worry about this for now
20 | /*
21 | プログラムの定数はモジュールレベル(関数の外)で、「const 」構造体として定義します。
22 | - 定数の型指定にはsnake_caseを使用することを勧めます。
23 | - constは他の言語よりも(寛大で)柔軟です。
24 | - グローバル変数に替え、const構造体に複雑なデータ型を作成することができます。
25 | */
26 | const (
27 | hello = 'hello'
28 | world = 'world'
29 | age_of_world = 42
30 | )
31 |
32 | // Cと同じく、構造体により、異なるデータ型のグループを1つの論理型として定義できます。※pubにより公開public
33 | struct Address {
34 | pub:
35 | street string
36 | city string
37 | state string
38 | zip int
39 | }
40 |
41 | // ソース・コード全体で複数の定数宣言が可能です。が、同じ領域でできるだけ多く宣言することをお勧めします。
42 | const (
43 | streets = ['1234 Alpha Avenue', '9876 Test Lane']
44 | address = Address{
45 | street: streets[0]
46 | city: 'Beta'
47 | state: 'Gamma'
48 | zip: 31416
49 | }
50 | address2 = Address{
51 | street: streets[1]
52 | city: 'Exam'
53 | state: 'Quiz'
54 | zip: 62832
55 | }
56 | )
57 |
58 | /*
59 | 関数宣言は、他言語の近しい形式に従います:
60 | fn function_name(param_list) return_type_list {
61 | function_body
62 | }
63 | */
64 | // パラメータを個別に宣言する必要があります
65 | fn make_new_address(street string, city string, state string, zip int) Address {
66 | return Address{
67 | street: street
68 | city: city
69 | state: state
70 | zip: zip
71 | }
72 | }
73 |
74 | const (
75 | address3 = make_new_address('2718 Tau Dr', 'Turing', 'Leibniz', 54366)
76 | address4 = make_new_address('3142 Uat Rd', 'Einstein', 'Maxwell', 62840)
77 | )
78 |
79 | // ただし、Vの末尾の構造体構文を使用して構造体をすばやく初期化すると、関数の文書化に役立ちます。
80 | struct AddressConfig {
81 | pub:
82 | /*
83 | この目的で使用される構造体の名前は{StructName} Configであるという慣習があります
84 |
85 | 構造体のフィールドにはデフォルト値を設定できるため、これらはConfigStructで設定するのが一般的です。
86 | */
87 | street string = '1234 Default St'
88 | city string = 'Your Favorite City'
89 | state string = 'Could Be Any'
90 | zip int = 42 // <--- always the answer (....at least some supercomputer says so...)
91 | }
92 |
93 | fn new_address(cfg AddressConfig) &Address {
94 | return &Address{
95 | street: cfg.street
96 | city: cfg.city
97 | state: cfg.state
98 | zip: cfg.zip
99 | }
100 | }
101 |
102 | const (
103 | default_address = new_address(AddressConfig{})
104 | initialized_address = new_address(
105 | street: '0987 tluafeD tS'
106 | city: 'ytiC etirovaF rouY'
107 | state: 'ynA eB dluoC'
108 | zip: 24
109 | )
110 | )
111 |
112 | /*
113 | 構造体は、Golangと同じく、メソッドと呼ばれる特殊な関数を持つことができます。
114 | メソッドは通常の関数と同様ですが、(構造体を示す)特別なreceiver引数を持ちます。
115 | receiver引数のパラメーター名は短くしましょう(通常は1文字、以下ではa)。
116 | */
117 | fn (a Address) str() string {
118 | return 'Address.str(): $a.street, $a.city, $a.state $a.zip'
119 | }
120 |
121 | struct Point {
122 | x_coor int
123 | y_coor int
124 | }
125 |
126 | fn test_out_of_order_calls() {
127 | // 他の多くの言語とは異なり、変数は関数スコープでのみ定義できます。
128 | point := Point{
129 | x_coor: 2
130 | y_coor: 2
131 | }
132 | // 変数はデフォルトで不変で、mutをつけると可変になります。
133 | mut point1 := Point{}
134 | // = は、代入
135 | point1 = Point{
136 | x_coor: 1
137 | y_coor: 1
138 | }
139 | // := は、変数を初期化
140 | x_diff, y_diff, distance := point.dist(point1)
141 | // 関数を宣言の前に使用できます(ヘッダファイルの必要性を軽減)。
142 | println('difference in:\nx_coors = $x_diff, y_coors = $y_diff\nthe distance between them is ${distance:.2f}')
143 | }
144 |
145 | fn (p Point) dist(p2 Point) (f64, f64, f64) {
146 | // T (v) の形式で型変換を実行できます。以下では、f64(int型)で、int=>f64の型変換
147 | x_diff_immutable := f64(p2.x_coor - p.x_coor)
148 | // x_diff_immutable = 2 // would cause a compile error (test it, I'll wait ;] )
149 | mut y_diff_mutable := f64(p2.y_coor - p.y_coor)
150 | // 今お気づきのように、mutキーワードは、変数が変更可能(変更可能)であることを示します
151 | mut distance := math.pow(x_diff_immutable, 2)
152 | y_diff_mutable = math.pow(y_diff_mutable, 2)
153 | // これにより、変数が初期化された後、変数に新しい値を割り当てることができます
154 | distance = distance + y_diff_mutable
155 | distance = math.sqrt(distance)
156 | // 当然ながら : distance = math.sqrt(distance + y_diff_mutable)
157 | return x_diff_immutable, y_diff_mutable, distance
158 | }
159 |
160 | fn string_example() {
161 | // 文字は一連のバッククォート( `)で示されます(多くのPCでは、これはエスケープの下のキーです)
162 | a_char := `a`
163 | //既出の通りが、補間文字列(interpolated strings)が、ディフォルトで利用できます(変数のみの場合、直接補間:例 $x)。
164 | println('The ascii value of this char is: $a_char')
165 | // より高度な補間には${to_be_interpolated}が必要です
166 | println('The char is: $a_char.str()')
167 | // 必要に応じ、+による連結も使用できます。
168 | mut concat := 'b' + a_char.str() + 'dnews be' + a_char.str() + 'rs'
169 | print(concat)
170 | // use += 文字列への追加
171 | concat += '_appended'
172 | println(', $concat')
173 | }
174 |
175 | fn arrays_example() {
176 | // 配列は、単一のデータ型のコレクションです
177 | mut fruits := ['apple', 'banana', 'cherry']
178 | // データ型は、最初に含まれる要素の型によって決まります。
179 | println(fruits)
180 | // << により、mutな配列の末尾に追加します。
181 | fruits << 'kiwi'
182 | println(fruits)
183 | // 配列の領域は、事前に割り当て可能です。
184 | ben_10 := ['ben'].repeat(10)
185 | // 配列の長さは .len によって取得します。
186 | // 配列名[インデックス]の形式で、インデックス番目の要素を取得します(インデックスは0始まり)。
187 | println('There are $ben_10.len occurrences of ${ben_10[0]} in \n' + ben_10.str())
188 | }
189 |
190 | fn maps_example() {
191 | // mapは、他の多くの言語の辞書(pythonでいうdict)のように機能します。
192 | mut my_dict := map[string]f64{} // 現時点の制限: 文字列のみをキーとして受け付けます。
193 | my_dict['pi'] = 3.14 // 値には、任意の型が使用できます。
194 | my_dict['tau'] = 6.28
195 | my_dict['e'] = 2.72
196 | println(my_dict.str())
197 | println('alt_dictの例: キーと値のペアを、この代替初期化フォームで定義できます。')
198 | alt_dict := map{
199 | 'a': 1.1
200 | 'b': 2.2
201 | 'c': 3.3
202 | }
203 | println(alt_dict.str())
204 | }
205 |
206 | /*
207 | if-else条件は、値やプログラムの状態をチェックする必要がある場合に非常に便利です。Golangに似ています。:
208 | if some_condition { // ※現バージョンでは、条件は括弧では囲みません。
209 | some_conditionが真である場合に実行される文 // 文は、中括弧で囲います。
210 | }
211 | else if some_other_condition {
212 | some_conditionが偽かつsome_other_conditionが真である場合に実行される文
213 | }
214 | else {
215 | いずれの条件でもない場合に実行される文
216 | }
217 | */
218 | fn conditional_example() {
219 | a := 15
220 | b := 35
221 | // 条件を囲む括弧は、長い式に役立ちます
222 | if b == 2 * a {
223 | println('b ($b) is twice the value of a ($a)')
224 | } else if a > b { // ただし、必須ではありません
225 | println('a ($a) is greater than b ($b)')
226 | } else {
227 | println('a ($a) is less than or equal to b ($b)')
228 | }
229 | // if-else節は式として、評価結果を変数に格納できます。
230 | mult_of_3 := if a % 3 == 0 {
231 | 'a ($a) is a multiple of 3'
232 | } else {
233 | 'a ($a) is NOT a multiple of 3'
234 | }
235 | println(mult_of_3)
236 | c := `c` // 他の結果を表示するには、これを変更してください
237 | mut x := ''
238 | // if c==`a`の省略形として、match文があります(他の言語のswitch文に類似)。
239 | match c {
240 | `a` {
241 | println('$c.str() is for Apple')
242 | x += 'Apple'
243 | }
244 | `b` {
245 | println('$c.str() is for Banana')
246 | x += 'Banana'
247 | }
248 | `c` {
249 | println('$c.str() is for Cherry')
250 | x += 'Cherry'
251 | }
252 | else {
253 | println('NOPE')
254 | }
255 | }
256 | println(x)
257 | }
258 |
259 | /*
260 | in演算子は、要素が配列またはmapのメンバであるかどうかをチェックするために使用します。
261 | */
262 | fn in_example() {
263 | arr := [1, 2, 3, 5]
264 | // 指定した要素(4)が、配列内の要素に存在するかどうかを調べます。
265 | x := if 4 in arr { 'There was a 4 in the array' } else { 'There was not a 4 in the array' }
266 | println(x)
267 | m := map{
268 | 'ford': 'mustang'
269 | 'chevrolet': 'camaro'
270 | 'dodge': 'challenger'
271 | }
272 | // 指定した要素('chevrolet')が、map内の要素に存在するかどうかを調べます。
273 | y := if 'chevrolet' in m {
274 | 'The chevrolet in the list is a ' + m['chevrolet']
275 | } else {
276 | 'There were no chevrolets in the list :('
277 | }
278 | println(y)
279 | }
280 |
281 | fn for_loop_examples(m map[string]f64) string {
282 | mut result := ''
283 | // Vにはwhileループがありません。forループには、利用できるいくつかの形式があります
284 | mut count := 0
285 | num_keys := m.len
286 | println('Number of keys in the map $num_keys')
287 | // 形式1 forのみを記すと、無限ループとなります。
288 | for {
289 | count += 2
290 | println(num_keys.str())
291 | if count == num_keys - 1 {
292 | // break文に到達するまず実行されます(またはcompがリソースを使い果たすまで:])
293 | break
294 | } else if count == 6 {
295 | // continueステートメントはループの次へとスキップします。
296 | continue
297 | }
298 | result += 'Count is $count'
299 | }
300 | //形式2 標準的なforループ
301 | for i := 1; i <= 10; i++ {
302 | if i % 2 == 0 {
303 | println('i ($i) is even')
304 | }
305 | }
306 | //形式3-1 (pythonと同様の)for...in... ※他言語のforeachのようにふるまいます
307 | for val in [1, 2, 3] {
308 | result += '$val '
309 | }
310 | result += '\n'
311 | //形式3-2 (pythonと同様の)for key, val in... ※foreachの特別版
312 | for key, val in m {
313 | result += 'key: $key -> value: $val '
314 | }
315 | // 最後の1つ(3-2)は、マップや配列のインデックスが必要な場合に非常に便利です
316 | return result
317 | }
318 |
319 | /*
320 | Defer文を使用して、周囲のコードが終了した後に実行されるコードを宣言できます。
321 | */
322 | fn defer_example() {
323 | mut a := f64(3)
324 | mut b := f64(4)
325 | // このブロック内のすべてのものは、スコープ内のコードの実行が完了するまで実行されません。
326 | defer {
327 | c := math.sqrt(a + b)
328 | println('コードが完了したので最後に実行: The hypotenuse of the triangle is $c')
329 | }
330 | // これらは上記の文より前に実行されます。
331 | a = math.pow(a, 2)
332 | b = math.pow(b, 2)
333 | print('square of the length of side A is $a')
334 | println(', square of the length of side B is $b')
335 | }
336 |
337 | struct DivisionResult {
338 | result f64
339 | }
340 |
341 | /*
342 | 戻りの型指定の前に?を付けるとOption型となります(vでの標準的なエラー処理の仕組み)
343 | */
344 | fn divide(a f64, b f64) ?DivisionResult {
345 | if b != 0 {
346 | return DivisionResult{
347 | result: a / b
348 | }
349 | }
350 | return error("Can't divide by zero!")
351 | }
352 |
353 | fn error_handling_example() {
354 | x := f64(10.0)
355 | y := f64(0)
356 | z := f64(2.5)
357 | fail := divide(x, y) or {
358 | // 「or 」句において、エラー発生時の状況を特別値errはを介して取得できます:
359 | // (err is a special value for the 'or' clause that corresponds to the text in the error statement)
360 | println(err)
361 | // 「or 」句はreturn、break、または、continue文で終わる必要があります。
362 | // ※break、continueはforループ内で、と中断、続行として使用
363 | return
364 | }
365 | // succeedには成功時の値が入る
366 | succeed := divide(x, z) or {
367 | println(err)
368 | return
369 | }
370 | println(succeed.result)
371 | }
372 |
373 | /*
374 | シングルファイルプログラムは、mainなしで実行できます。
375 | これは、クロスプラットフォームのスクリプトを作成する場合に非常に便利です。
376 | println('$hello $world, you are $age_of_world days old.')
377 | println(streets)
378 | println('$address.street, $address.city, $address.state $address.zip')
379 | println('$address2.street, $address2.city, $address2.state')
380 | println(address3.str())
381 | println(address4.str())
382 | println(default_address)
383 | println(initialized_address)
384 | test_out_of_order_calls()
385 | string_example()
386 | arrays_example()
387 | maps_example()
388 | conditional_example()
389 | in_example()
390 | defer_example()
391 | error_handling_example()
392 | */
393 | fn main() {
394 | /*
395 | 前のコードのコメントを解除し、main関数を削除して、単一ファイルプログラムをテストできます。
396 | */
397 | println('$hello $world, you are $age_of_world days old.')
398 | println(streets)
399 | println('$address.street, $address.city, $address.state $address.zip')
400 | println('$address2.street, $address2.city, $address2.state')
401 | println(address3.str())
402 | println(address4.str())
403 | println(default_address)
404 | println(initialized_address)
405 | test_out_of_order_calls()
406 | string_example()
407 | arrays_example()
408 | maps_example()
409 | conditional_example()
410 | in_example()
411 | defer_example()
412 | error_handling_example()
413 | }
414 |
--------------------------------------------------------------------------------
/learnv.v:
--------------------------------------------------------------------------------
1 | // single-line comments start with a //
2 | /*
3 | multi-line comments start with a /*
4 | and they can be nested */
5 | */
6 | /*
7 | V's basic data types include:
8 | bool - true/false
9 | string - 'hello' *utf-8 encoded*
10 | i8 i16 int i64 i128[WIP] - signed integers of 8, 16, 32, 64, and 128 bits
11 | byte u16 u32 u64 u128[WIP] - unsigned integers of 8, 16, 32, 64, and 128 bits
12 | f32 f64 - floating point numbers of 32 and 64 bits
13 | rune - unicode code point (unicode equivalent of an ascii char)
14 | byteptr
15 | voidptr
16 | Note from the Developer: Unlike C and Go, int is always 32 bits
17 | */
18 | // packages from the standard library and any packages installed through vpm
19 | // are loaded at the start of a program
20 | import math
21 |
22 | // don't worry about the import for now
23 | // program constants are defined at the module level (External to any functions) and are denoted by the 'const' structure
24 | const (
25 | hello = 'hello'
26 | world = 'world'
27 | age_of_world = 42
28 | )
29 |
30 | /*
31 | snake_case is the preferred typing method for constants
32 | const's are more lenient and flexible than in other languages
33 | To promote the lack of global variables, complex data types can be created in the consts structure
34 | */
35 | /*
36 | structs, like in C, allow you define a group of different data-types together in a single, logical type
37 | more advanced features will be covered shortly
38 |
39 | structs store variables known as fields, which are immutable(cannot be changed) and private(only accessible by methods of the struct) by default,
40 | use mut and pub to change their state.
41 | */
42 | struct Address {
43 | pub: // creates publically available fields that cannot be changed
44 | street string
45 | city string
46 | state string
47 | zip int
48 | }
49 |
50 | /*
51 | There can be multiple constant declarations throughout source code;
52 | although it is recommended to declare as many as possible in the same area
53 | */
54 | const (
55 | streets = ['1234 Alpha Avenue', '9876 Test Lane']
56 | address = Address{
57 | street: streets[0]
58 | city: 'Beta'
59 | state: 'Gamma'
60 | zip: 31416
61 | }
62 | address2 = Address{
63 | street: streets[1]
64 | city: 'Exam'
65 | state: 'Quiz'
66 | zip: 62832
67 | }
68 | )
69 |
70 | /*
71 | Function declarations follow many other languages' form:
72 | fn function_name(param_list) return_type_list {
73 | function_body
74 | }
75 | */
76 | // You must declare parameters individually
77 | fn make_new_address(street string, city string, state string, zip int) Address {
78 | return Address{
79 | street: street
80 | city: city
81 | state: state
82 | zip: zip
83 | }
84 | }
85 |
86 | const (
87 | address3 = make_new_address('2718 Tau Dr', 'Turing', 'Leibniz', 54366)
88 | address4 = make_new_address('3142 Uat Rd', 'Einstein', 'Maxwell', 62840)
89 | )
90 |
91 | // although, you can quickly initialize structs using V's trailing struct shortcut, shown below, to help in better documenting functions.
92 | struct AddressConfig {
93 | pub:
94 | /*
95 | Convention holds that structs used for this purpose are named {StructName}Config
96 |
97 | A struct's fields can have default values, so it's common to set these in the Config Struct
98 | */
99 | street string = '1234 Default St'
100 | city string = 'Your Favorite City'
101 | state string = 'Could Be Any'
102 | zip int = 42 // <--- always the answer (....at least some supercomputer says so...)
103 | }
104 |
105 | fn new_address(cfg AddressConfig) &Address {
106 | return &Address{
107 | street: cfg.street
108 | city: cfg.city
109 | state: cfg.state
110 | zip: cfg.zip
111 | }
112 | }
113 |
114 | const (
115 | // This is using the trailing struct shortcut, mentioned above
116 | default_address = new_address(AddressConfig{})
117 | initialized_address = new_address(
118 | street: '0987 tluafeD tS'
119 | city: 'ytiC etirovaF rouY'
120 | state: 'ynA eB dluoC'
121 | zip: 24
122 | )
123 | )
124 |
125 | /*
126 | Structs have special functions called methods.
127 | They are like any regular function with the addition of having a special receiver argument.
128 | Conventionally, the parameter name for the receiver should be short (typically a single letter)
129 | */
130 | fn (a Address) str() string {
131 | return 'Address.str(): $a.street, $a.city, $a.state $a.zip'
132 | }
133 |
134 | struct Point {
135 | x_coor int
136 | y_coor int
137 | }
138 |
139 | fn test_out_of_order_calls() {
140 | // unlike most languages, variables can only be defined in a function scope
141 | point := Point{
142 | x_coor: 2
143 | y_coor: 2
144 | }
145 | // Variables are immutable by default
146 | mut point1 := Point{}
147 | // := is used for initialization, = is an assignment
148 | point1 = Point{
149 | x_coor: 1
150 | y_coor: 1
151 | }
152 | x_diff, y_diff, distance := point.dist(point1)
153 | // A function can be used before their declaration to alleviate the need for header files
154 | println('difference in:\nx_coors = $x_diff, y_coors = $y_diff\nthe distance between them is ${distance:.2f}')
155 | }
156 |
157 | fn (p Point) dist(p2 Point) (f64, f64, f64) {
158 | // you can perform type conversion with the T(v) form
159 | // the following is int => f64 using the form f64(int)
160 | x_diff_immutable := f64(p2.x_coor - p.x_coor)
161 | // x_diff_immutable = 2 // would cause a compile error (test it, I'll wait ;] )
162 | mut y_diff_mutable := f64(p2.y_coor - p.y_coor)
163 | // as you've realized now, the mut keyword denotes that a variable should be mutable
164 | mut distance := math.pow(x_diff_immutable, 2)
165 | y_diff_mutable = math.pow(y_diff_mutable, 2)
166 | // that allows us to assign a new value to a variable after it's initialized
167 | distance = distance + y_diff_mutable
168 | distance = math.sqrt(distance)
169 | // Naturally: distance = math.sqrt(distance + y_diff_mutable)
170 | return x_diff_immutable, y_diff_mutable, distance
171 | }
172 |
173 | fn string_example() {
174 | // a char is denoted by a set of backticks ( ` ) (on many PCs this is the key under escape)
175 | a_char := `a`
176 | // you've seen examples, but interpolated strings are readily available
177 | println('The ascii value of this char is: $a_char')
178 | // basic values can be interpolated directly,
179 | // more advanced interpolations require ${to_be_interpolated}
180 | println('The char is: $a_char.str()')
181 | // if you prefer, concatenation is always available
182 | mut concat := 'b' + a_char.str() + 'dnews be' + a_char.str() + 'rs'
183 | print(concat)
184 | // use += to append to a string
185 | concat += '_appended'
186 | println(', $concat')
187 | }
188 |
189 | fn arrays_example() {
190 | // arrays are collections of a SINGLE data type
191 | mut fruits := ['apple', 'banana', 'cherry']
192 | // the data type is determined by the type of the first element that it contains
193 | println(fruits)
194 | // use << to append to the end
195 | fruits << 'kiwi'
196 | println(fruits)
197 | // arrays can be pre-allocated
198 | ben_10 := ['ben'].repeat(10)
199 | // use .len to get the number of elements in an array
200 | // use array_name[desired_index] to get the element at a specific index (indices start at 0)
201 | println('There are $ben_10.len occurrences of ${ben_10[0]} in \n' + ben_10.str())
202 | }
203 |
204 | fn maps_example() {
205 | // maps function like dictionaries from many other languages
206 | mut my_dict := map[string]f64{} // Maps can have keys of type string, rune, integer, float or voidptr
207 | my_dict['pi'] = 3.14
208 | my_dict['tau'] = 6.28 // but any type can be used as a value
209 | my_dict['e'] = 2.72
210 | // if you know some/all of the key-value pairs, this alternative initialization form may come in hand
211 | // alt_dict := {'a' : 1.1, 'b' : 2.2, 'c' : 3.3}
212 | // println(alt_dict.str())
213 | println(my_dict)
214 | for_loop_examples(my_dict)
215 | }
216 |
217 | /*
218 | Conditionals are extremely useful when needing to check values or the state of your program.
219 | The standard if-else suite functions like many other languages:
220 | if some_condition {
221 | statements to perform when some_condition is true
222 | }
223 | else if some_other_condition {
224 | statements to execute when some_condition is false
225 | and some_other_condition is true
226 | }
227 | else {
228 | statements to perform if neither condition is valid
229 | }
230 | */
231 | fn conditional_example() {
232 | a := 15
233 | b := 35
234 | // parentheses around the condition can be useful for longer expressions
235 | if b == 2 * a {
236 | println('b ($b) is twice the value of a ($a)')
237 | } else if a > b { // however they are not required
238 | println('a ($a) is greater than b ($b)')
239 | } else { // the curly braces are though
240 | println('a ($a) is less than or equal to b ($b)')
241 | }
242 | // if-else suites can be used as an expression and the result stored in a variable
243 | mult_of_3 := if a % 3 == 0 {
244 | 'a ($a) is a multiple of 3'
245 | } else {
246 | 'a ($a) is NOT a multiple of 3'
247 | }
248 | println(mult_of_3)
249 | c := `c` // change this to see other results
250 | mut x := ''
251 | // a shorthand to if c == `a` is v's match statement
252 | // it is similar to many other languages' switch statement
253 | match c {
254 | `a` {
255 | println('$c.str() is for Apple')
256 | x += 'Apple'
257 | }
258 | `b` {
259 | println('$c.str() is for Banana')
260 | x += 'Banana'
261 | }
262 | `c` {
263 | println('$c.str() is for Cherry')
264 | x += 'Cherry'
265 | }
266 | else {
267 | println('NOPE')
268 | }
269 | }
270 | println(x)
271 | }
272 |
273 | /*
274 | The in operator is used to check if an element is a member in an array or map
275 | */
276 | fn in_example() {
277 | arr := [1, 2, 3, 5]
278 | // for arrays, 'in' checks if a specified element is a value stored in it
279 | x := if 4 in arr { 'There was a 4 in the array' } else { 'There was not a 4 in the array' }
280 | println(x)
281 | m := map{
282 | 'ford': 'mustang'
283 | 'chevrolet': 'camaro'
284 | 'dodge': 'challenger'
285 | }
286 | // for maps, 'in' checks if a specified element is a key of the map
287 | y := if 'chevrolet' in m {
288 | 'The chevrolet in the list is a ' + m['chevrolet']
289 | } else {
290 | 'There were no chevrolets in the list :('
291 | }
292 | println(y)
293 | }
294 |
295 | fn for_loop_examples(m map[string]f64) string {
296 | mut result := ''
297 | // V has no while loop, for loops have several forms that can be utilized
298 | mut count := 0
299 | num_keys := m.len
300 | println('Number of keys in the map $num_keys')
301 | // the basic for loop will run indefinitely
302 | for {
303 | count += 2
304 | println(num_keys.str())
305 | if count == num_keys - 1 {
306 | // until it reaches a break statement...or the comp runs out of resources :]
307 | break
308 | } else if count == 6 {
309 | // continue statements skip to the next iteration of the loop
310 | continue
311 | }
312 | result += 'Count is $count'
313 | }
314 | // the more standard for loop is available as well
315 | for i := 1; i <= 10; i++ {
316 | if i % 2 == 0 {
317 | println('i ($i) is even')
318 | }
319 | }
320 | // the for...in... acts like the foreach of most languages
321 | for val in [1, 2, 3] {
322 | result += '$val '
323 | }
324 | result += '\n'
325 | // the for key, val in... is a specialized version of the 'foreach' loop
326 | for key, val in m {
327 | result += 'key: $key -> value: $val '
328 | }
329 | // the last one is very handy for maps or when the index in arrays is needed
330 | return result
331 | }
332 |
333 | /*
334 | Defer statements permit you to declare code that will run after the surrounding code has finished
335 | */
336 | fn defer_example() {
337 | mut a := f64(3)
338 | mut b := f64(4)
339 | // anything within this block won't run until the code after it has completed
340 | defer {
341 | c := math.sqrt(a + b)
342 | println('The hypotenuse of the triangle is $c')
343 | }
344 | // this should be executed before the statements above
345 | a = math.pow(a, 2)
346 | b = math.pow(b, 2)
347 | print('square of the length of side A is $a')
348 | println(', square of the length of side B is $b')
349 | }
350 |
351 | struct DivisionResult {
352 | result f64
353 | }
354 |
355 | /*
356 | Option Type is the standard error handling mechanism in v
357 | They are denoted with a ? on the return type
358 | */
359 | fn divide(a f64, b f64) ?DivisionResult {
360 | if b != 0 {
361 | return DivisionResult{
362 | result: a / b
363 | }
364 | }
365 | return error("Can't divide by zero!")
366 | }
367 |
368 | fn error_handling_example() {
369 | x := f64(10.0)
370 | y := f64(0)
371 | z := f64(2.5)
372 | fail := divide(x, y) or {
373 | // err is a special value for the 'or' clause that corresponds to the text in the error statement
374 | println(err)
375 | // 'or' blocks must end with a return, break, or continue statements.
376 | // the last two (break and continue) must be in a for loop of some kind
377 | return
378 | }
379 | /*
380 | // comment the fail block and uncomment this block if you want to see the division succeed
381 | succeed := divide(x, z) or {
382 | println(err)
383 | return
384 | }
385 | println(succeed.result)
386 | */
387 | }
388 |
389 | /*
390 | Single File programs can do without a main function as an entry point
391 | This is extremely useful for making cross-platform scripts
392 | println('$hello $world, you are $age_of_world days old.')
393 | println(streets)
394 | println('$address.street, $address.city, $address.state $address.zip')
395 | println('$address2.street, $address2.city, $address2.state')
396 | println(address3.str())
397 | println(address4.str())
398 | println(default_address)
399 | println(initialized_address)
400 | test_out_of_order_calls()
401 | string_example()
402 | arrays_example()
403 | maps_example()
404 | conditional_example()
405 | in_example()
406 | defer_example()
407 | error_handling_example()
408 | */
409 | fn main() {
410 | /*
411 | You can uncomment the prior code and remove the main function to test Single File programs.
412 | */
413 | println('$hello $world, you are $age_of_world days old.')
414 | println(streets)
415 | println('$address.street, $address.city, $address.state $address.zip')
416 | println('$address2.street, $address2.city, $address2.state')
417 | println(address3.str())
418 | println(address4.str())
419 | println(default_address)
420 | println(initialized_address)
421 | test_out_of_order_calls()
422 | string_example()
423 | arrays_example()
424 | maps_example()
425 | conditional_example()
426 | in_example()
427 | defer_example()
428 | error_handling_example()
429 | }
430 |
--------------------------------------------------------------------------------