Если вы уже наигрались с Go, устали от копипасты, ручного жонглирования типами и подумываете вернуться на какой-нибудь Python или, прости господи, PHP, то позвольте предложить вам попробовать язык D, где типизация хоть и тоже статическая, но она не путается под ногами и позволяет писать не менее выразительный код, чем на языках с динамической типизацией. А чтобы переход был не такой болезненный, вашему вниманию предлагается перевод Tour of the Go c эквивалентным кодом на D и краткими пояснениями.
Разница не значительная, разве что в D пространство имён можно не указывать, если нет конфликта имён импортированных из разных модулей. Также стоит обратить внимание на обязательные точки с запятыми в конце строк - в D они, к сожалению, обязательны.
module main;
import std.stdio;
import std.random;
void main()
{
writeln( "My favorite number is ", uniform( 0 , 10 ) );
}
Тут тоже всё одинаково, разве что в Go при импорте указывается путь к модулю, а в D используется имя модуля, задаваемое директивой "module", или автоматически выводимое из пути к файлу, если эта директива не указана.
module main;
import std.stdio;
import std.typecons;
auto split( int sum )
{
auto x = sum * 4 / 9;
auto y = sum - x;
return tuple!( "x" , "y" )( x , y );
}
void main()
{
// auto res = split( 17 ); writeln( res.x , res.y );
// writeln( split( 17 )[] );
writeln( 17.split[] ); // 710
}
Оператор [] возвращает так называемый "срез", то есть массив элементов.
module main;
import std.stdio;
void main()
{
int i = 1 , j = 2;
auto k = 3;
auto c = true , python = false , java = "no!";
writeln( i , j , k , c , python , java ); // 123truefalseno!
}
Оба языка умеют выводить тип переменной из инициализирующего выражения. Однако подход Go с разделением объявления переменных на список имён и список значений довольно не нагляден и провоцирует ошибки.
Basic types
Таблица соответствия типов:
Go D
---------------------
void
bool bool
string string
int int
byte byte
int8 byte
int16 short
int32 int
int64 long
uint unint
uint8 ubyte
uint16 ushort
uint32 uint
uint64 ulong
uintptr size_t
ptrdiff_t
float32 float
float64 double
real
ifloat
idouble
ireal
complex64 cfloat
complex128 cdouble
creal
char
wchar
rune dchar
Существенное различие в том, что размер int и uint в Go зависит от платформы, а в D - не зависит. Также D контролирует, чтобы мнимые числа не перепутались с реальными. Кроме того, D позволяет работать с вещественными числами большего размера (80 бит), а с символами - меньшего (8 и 16 бит). Подробнее о типах в D.
module main;
import std.stdio;
import std.math;
bool ToBe = false;
ulong MaxInt = ulong.max;
cdouble z = sqrt( -5 + 12i );
void main()
{
enum f = "%s(%s)";
writefln( f , typeid( ToBe ) , ToBe ); // bool(false)
writefln ( f , typeid( MaxInt ) , MaxInt ); // ulong(18446744073709551615)
writefln( f , typeid( z ) , z ); // cdouble(2+3i)
}
В D у каждого типа есть свойства, позволяющие получить основные связанные с типом константы. Стоит обратить внимание, что в D константы времени компиляции создаются через ключевое слово "enum" - их значение инлайнится в место их использования. А вот ключевое слово "const" имеет несколько иное значение - это модификатор доступа, запрещающий нам изменять значение переменной (но в другом месте программы у нас может быть доступ на редактирование).
package main
import (
"fmt"
"math"
)
func main() {
var x int = 3
var y uint = 4
var f float64 = math.Sqrt(float64(uint(x*x) + y*y))
var z uint = uint(f)
fmt.Println(x, y, z) // 345
}
module main;
import std.stdio;
import std.conv;
void main()
{
int x = 3;
uint y = 4;
double f = ( x^^2 + y^^2 )^^0.5;
uint z = f.to!uint;
writeln( x , y , z ); // 345
}
package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small)) // 21
fmt.Println(needInt(Big)) // constant 1267650600228229401496703205376 overflows int
fmt.Println(needFloat(Small)) // 0.2
fmt.Println(needFloat(Big)) // 1.2676506002282295e+29
}
https://page.hyoo.ru/#!=kar47j_vn98si
Если вы уже наигрались с Go, устали от копипасты, ручного жонглирования типами и подумываете вернуться на какой-нибудь Python или, прости господи, PHP, то позвольте предложить вам попробовать язык D, где типизация хоть и тоже статическая, но она не путается под ногами и позволяет писать не менее выразительный код, чем на языках с динамической типизацией. А чтобы переход был не такой болезненный, вашему вниманию предлагается перевод Tour of the Go c эквивалентным кодом на D и краткими пояснениями.
Часть первая. Основы.
Hello World
Go
D
Разница не значительная, разве что в D пространство имён можно не указывать, если нет конфликта имён импортированных из разных модулей. Также стоит обратить внимание на обязательные точки с запятыми в конце строк - в D они, к сожалению, обязательны.
Packages
Go
D
Тут тоже всё одинаково, разве что в Go при импорте указывается путь к модулю, а в D используется имя модуля, задаваемое директивой "module", или автоматически выводимое из пути к файлу, если эта директива не указана.
Imports
В Go рекомендуется группировать импорты в одну директиву.
В D тоже так можно, но особенности синтаксиса не располагают к этому:
Кроме того, в D импорты можно указывать в любом блоке, а не только в начале файла:
Exported names
В Go модуль экспортирует лишь то, что начинается с большой буквы:
В D же экспортируется лишь то, что объявлено в public секции модуля (которая по умолчанию), либо помечено модификатором доступа public:
Подробнее о модульной системе D.
Functions
Go
D
В Go тип обычно следует в конце, а в D - более традиционно - в начале. Кроме того, любую функцию в D можно вызвать как метод, что позволяет элегантно расширять сторонние типы. Go же позволяет не повторять одинаковые типы идущих друг за другом параметров. Тут же стоит упомянуть отсутствующее в Go обобщённое программирование, позволяющее реализовать функцию сразу для любых подходящих типов:
В D для любой функции можно указать в дополнительных круглых скобках параметры времени компиляции, куда можно либо явно передать типы, либо они могут быть выведены автоматически компилятором из типов аргументов.
Multiple results
Go
В D нет возможности возвратить из функции несколько отдельных значений, но можно вернуть кортеж:
А при необходимости можно и распаковать возвращаемый кортеж в уже существующие переменные:
Named return values
Go
Достаточно сомнительный синтаксический сахар. D ничего такого не поддерживает, так что возвращаем либо структуру, либо опять же кортеж, но с именованными элементами:
Оператор [] возвращает так называемый "срез", то есть массив элементов.
Подробнее о кортежах в D.
Variables
Go
D
В целом, объявления переменных очень похожи, разве что синтаксис Go несколько более многословен.
Short variable declarations
Go
D
Оба языка умеют выводить тип переменной из инициализирующего выражения. Однако подход Go с разделением объявления переменных на список имён и список значений довольно не нагляден и провоцирует ошибки.
Basic types
Таблица соответствия типов:
Существенное различие в том, что размер int и uint в Go зависит от платформы, а в D - не зависит. Также D контролирует, чтобы мнимые числа не перепутались с реальными. Кроме того, D позволяет работать с вещественными числами большего размера (80 бит), а с символами - меньшего (8 и 16 бит). Подробнее о типах в D.
Go
D
В D у каждого типа есть свойства, позволяющие получить основные связанные с типом константы. Стоит обратить внимание, что в D константы времени компиляции создаются через ключевое слово "enum" - их значение инлайнится в место их использования. А вот ключевое слово "const" имеет несколько иное значение - это модификатор доступа, запрещающий нам изменять значение переменной (но в другом месте программы у нас может быть доступ на редактирование).
Zero values
Go
D
В D у каждого типа есть специальное поле "init", хранящее значение по умолчанию для этого типа.
Type conversions
Go требует ручного перевода значения из одного типа в другой:
D достаточно умён, чтобы требовать ручного перевода типов лишь когда это может привести к потере данных:
Numeric Constants
Численные константы в Go позволяют задавать числа, которые невозможно использовать в рантайме без потерь:
В D при компиляции используются те же типы, что и при выполнении, так что и значения констант имеют те же ограничения: