This document provides an overview of ONNX and ONNX Runtime. ONNX is an open format for machine learning models that allows models to be shared across different frameworks and tools. ONNX Runtime is a cross-platform open source inference engine that runs ONNX models. It supports hardware acceleration and has a modular design that allows for custom operators and execution providers to extend its capabilities. The document discusses how ONNX helps with deploying machine learning models from research to production and how ONNX Runtime performs high performance inference through optimizations and hardware acceleration.
Leveraging the Android Open Accessory ProtocolGary Bisson
The document discusses the Android Open Accessory Protocol (AOA), which allows USB hardware to interact with an Android device without the Android device acting as a USB host. It covers the AOA 1.0 and 2.0 specifications, the Accessory Development Kit (ADK) hardware and software, and demonstrations of developing accessories that display pictures, allow audio playback, and even run Android themselves by leveraging AOA capabilities.
This document provides an agenda and notes for a 3-day AWS, Terraform, and advanced techniques training. Day 1 covers AWS networking, scaling techniques, automation with Terraform and covers setting up EC2 instances, autoscaling groups, and load balancers. Day 2 continues EC2 autoscaling, introduces Docker, ECS, monitoring, and continuous integration/delivery. Topics include IAM, VPC networking, NAT gateways, EC2, autoscaling policies, ECS clusters, Docker antipatterns, monitoring servers/applications/logs, and Terraform code structure. Day 3 will cover Docker, ECS, configuration management, Vault, databases, Lambda, and other advanced AWS and DevOps topics.
This document provides an overview of ONNX and ONNX Runtime. ONNX is an open format for machine learning models that allows models to be shared across different frameworks and tools. ONNX Runtime is a cross-platform open source inference engine that runs ONNX models. It supports hardware acceleration and has a modular design that allows for custom operators and execution providers to extend its capabilities. The document discusses how ONNX helps with deploying machine learning models from research to production and how ONNX Runtime performs high performance inference through optimizations and hardware acceleration.
Leveraging the Android Open Accessory ProtocolGary Bisson
The document discusses the Android Open Accessory Protocol (AOA), which allows USB hardware to interact with an Android device without the Android device acting as a USB host. It covers the AOA 1.0 and 2.0 specifications, the Accessory Development Kit (ADK) hardware and software, and demonstrations of developing accessories that display pictures, allow audio playback, and even run Android themselves by leveraging AOA capabilities.
This document provides an agenda and notes for a 3-day AWS, Terraform, and advanced techniques training. Day 1 covers AWS networking, scaling techniques, automation with Terraform and covers setting up EC2 instances, autoscaling groups, and load balancers. Day 2 continues EC2 autoscaling, introduces Docker, ECS, monitoring, and continuous integration/delivery. Topics include IAM, VPC networking, NAT gateways, EC2, autoscaling policies, ECS clusters, Docker antipatterns, monitoring servers/applications/logs, and Terraform code structure. Day 3 will cover Docker, ECS, configuration management, Vault, databases, Lambda, and other advanced AWS and DevOps topics.
This document discusses serverless computing and AWS Lambda. It provides an overview of virtual machines, containers, and serverless/functions as a service. It describes how AWS Lambda works, including how to author functions using various programming languages. It also discusses how to integrate Lambda with other AWS services like API Gateway, Step Functions, S3, DynamoDB and more. It introduces the AWS Serverless Application Repository and AWS SAM for defining serverless applications.
Flask is a micro web framework written in Python that allows developers to create web applications and APIs quickly. It is lightweight and extensible, allowing developers to add additional functionality through extensions. Flask applications are easy to get started with - they can be created with just a few lines of code. Common features like unit testing, database support, and template rendering are supported out of the box or through extensions.
YAML is a data serialization language that is human-friendly and designed for interacting well with programming languages. Unlike XML, YAML aims to be easily readable by humans for config files, logging, and messaging. YAML uses indentation rather than tags to indicate hierarchy. It supports common data structures like lists, dictionaries, and scalar values like strings and integers.
Cracking Pseudorandom Sequences Generators in Java ApplicationsPositive Hack Days
The document discusses cracking pseudorandom number sequences generated by Java's java.util.Random class. It begins by explaining why cracking these sequences is important, as they are commonly used to generate values like session IDs, passwords, and CAPTCHAs. It then provides background on Java and its popularity. The document analyzes the linear congruential generator algorithm used by java.util.Random and how its state can be brute forced to recover prior values. It introduces a tool called javacg that can crack java.util.Random number sequences and recover the internal state. The document describes javacg's usage and capabilities to crack different cases like nextInt, nextLong, and generate passwords. It also covers performance optimization
This presentation will give information about What is Serverless? What service is exposed by AWS to support Function as a Service. Lambda is AWS service which support serverless.
by Brent Rabowsky, Solutions Architect & Itzik Paz, Solutions Architect, AWS
As serverless architectures become more popular, customers need a framework of patterns to help them identify how they can leverage AWS to deploy their workloads without managing servers or operating systems. This session describes re-usable serverless patterns while considering costs. For each pattern, we provide operational and security best practices and discuss potential pitfalls and nuances. We also discuss the considerations for moving an existing server-based workload to a serverless architecture. The patterns use services like AWS Lambda, Amazon API Gateway, Amazon Kinesis Streams, Amazon Kinesis Analytics, Amazon DynamoDB, Amazon S3, AWS Step Functions, AWS Config, AWS X-Ray, and Amazon Athena. This session can help you recognize candidates for serverless architectures in your own organizations and understand areas of potential savings and increased agility. What’s new in 2017: using X-Ray in Lambda for tracing and operational insight; a pattern on high performance computing (HPC) using Lambda at scale; how a query can be achieved using Athena; Step Functions as a way to handle orchestration for both the Automation and Batch patterns; a pattern for Security Automation using AWS Config rules to detect and automatically remediate violations of security standards; how to validate API parameters in API Gateway to protect your API back-ends; and a solid focus on CI/CD development pipelines for serverless –that includes testing, deploying, and versioning (SAM tools).
Go is a statically typed, compiled programming language designed for building simple, reliable, and efficient software. Some key points:
- Go is natively compiled and uses static typing with type inference. It is targeted for system programming and server-side applications.
- It was created at Google in 2007 to address issues with other languages like dependency management, garbage collection, and support for concurrency.
- Popular users include Google, Docker, Dropbox, SoundCloud, and MongoDB. Domains it is used include distributed systems, cloud, web development, and systems programming.
- Key features include built-in concurrency and networking support, a rich standard library, and fast compilation. It aims to be
Celery is a Python-based distributed task queue that uses message queues like AMQP to asynchronously execute tasks across multiple machines. It provides features like task scheduling, retries, error handling, and integration with Django. Tasks are defined as Python functions decorated with the "@task" decorator. Workers process tasks from the queue and results are sent back via messages. Celery simplifies building asynchronous workflows in Python applications.
사내 발표자료 겸 만들었는데, ECS Fargate를 이용하실 분들이라면, 편리하게 쓰실 수 있도록 최대한 상세하게 만들어 보았습니다.
사실 CloudFormation 등 배포는 좀 더 편리하게 할 수 있지만, 회사 사정도 있고, 제가 일단 그런 기술을 너무 늦게 알았기 때문에 다루지는 않았습니다.
ONNX - The Lingua Franca of Deep LearningHagay Lupesko
ONNX aims to serve as a common intermediate representation (IR) format for neural network models to allow for interoperability across different frameworks and tools. It uses ProtocolBuffers for its binary format and defines operators and graphs. ONNX allows users to build models with one framework like PyTorch, export to ONNX, and load into another framework like MXNet for inference or further training. The MXNet Model Server also supports serving models in ONNX format.
Rest-assured is a 100% java-based, BDD style, test library that you can use for testing REST api's in java projects. These are the slides from the presentation and demo I give at the 2017 #JBCNConf Java conference in Barcelona.
Exploring Twitter's Finagle technology stack for microservices💡 Tomasz Kogut
This document summarizes a presentation about Finagle, Twitter's microservices technology stack. It discusses how Finagle addresses challenges with microservices like service discovery, load balancing, and request tracing across services. It presents Finagle's core abstractions like Futures, Services, and Filters. Services represent both clients and servers, and Filters can add functionality like retries and timeouts. The document also mentions Twitter Server, a framework for building Finagle-based servers that handles flags, logging, metrics and admin interfaces. Finally, it briefly introduces Finatra, which builds on Finagle and Twitter Server and adds features like dependency injection and routing.
The document discusses the Serverless Framework, which is a build tool that makes it easy to setup and invoke Lambda functions on AWS. It allows developers to manage multiple Lambda functions across different regions and stages, and share code between functions. The Serverless Framework supports Node.js, Python, Java/Scala and other runtimes. Functions are defined in a serverless.yml file along with triggers like HTTP events, S3 uploads, schedules and more. The framework handles deployments to AWS and other cloud providers.
This document provides an overview of the Go programming language. It discusses that Go was initially developed at Google in 2007 and is now an open source language used by many companies. The document then covers Why Go is useful, including its memory management, concurrency support, and cross-platform capabilities. It also summarizes some of Go's basic syntax like packages, functions, variables, types, and control structures. Finally, it discusses some key Go concepts like methods, interfaces, channels, and the net/http package.
This document discusses serverless computing and AWS Lambda. It provides an overview of virtual machines, containers, and serverless/functions as a service. It describes how AWS Lambda works, including how to author functions using various programming languages. It also discusses how to integrate Lambda with other AWS services like API Gateway, Step Functions, S3, DynamoDB and more. It introduces the AWS Serverless Application Repository and AWS SAM for defining serverless applications.
Flask is a micro web framework written in Python that allows developers to create web applications and APIs quickly. It is lightweight and extensible, allowing developers to add additional functionality through extensions. Flask applications are easy to get started with - they can be created with just a few lines of code. Common features like unit testing, database support, and template rendering are supported out of the box or through extensions.
YAML is a data serialization language that is human-friendly and designed for interacting well with programming languages. Unlike XML, YAML aims to be easily readable by humans for config files, logging, and messaging. YAML uses indentation rather than tags to indicate hierarchy. It supports common data structures like lists, dictionaries, and scalar values like strings and integers.
Cracking Pseudorandom Sequences Generators in Java ApplicationsPositive Hack Days
The document discusses cracking pseudorandom number sequences generated by Java's java.util.Random class. It begins by explaining why cracking these sequences is important, as they are commonly used to generate values like session IDs, passwords, and CAPTCHAs. It then provides background on Java and its popularity. The document analyzes the linear congruential generator algorithm used by java.util.Random and how its state can be brute forced to recover prior values. It introduces a tool called javacg that can crack java.util.Random number sequences and recover the internal state. The document describes javacg's usage and capabilities to crack different cases like nextInt, nextLong, and generate passwords. It also covers performance optimization
This presentation will give information about What is Serverless? What service is exposed by AWS to support Function as a Service. Lambda is AWS service which support serverless.
by Brent Rabowsky, Solutions Architect & Itzik Paz, Solutions Architect, AWS
As serverless architectures become more popular, customers need a framework of patterns to help them identify how they can leverage AWS to deploy their workloads without managing servers or operating systems. This session describes re-usable serverless patterns while considering costs. For each pattern, we provide operational and security best practices and discuss potential pitfalls and nuances. We also discuss the considerations for moving an existing server-based workload to a serverless architecture. The patterns use services like AWS Lambda, Amazon API Gateway, Amazon Kinesis Streams, Amazon Kinesis Analytics, Amazon DynamoDB, Amazon S3, AWS Step Functions, AWS Config, AWS X-Ray, and Amazon Athena. This session can help you recognize candidates for serverless architectures in your own organizations and understand areas of potential savings and increased agility. What’s new in 2017: using X-Ray in Lambda for tracing and operational insight; a pattern on high performance computing (HPC) using Lambda at scale; how a query can be achieved using Athena; Step Functions as a way to handle orchestration for both the Automation and Batch patterns; a pattern for Security Automation using AWS Config rules to detect and automatically remediate violations of security standards; how to validate API parameters in API Gateway to protect your API back-ends; and a solid focus on CI/CD development pipelines for serverless –that includes testing, deploying, and versioning (SAM tools).
Go is a statically typed, compiled programming language designed for building simple, reliable, and efficient software. Some key points:
- Go is natively compiled and uses static typing with type inference. It is targeted for system programming and server-side applications.
- It was created at Google in 2007 to address issues with other languages like dependency management, garbage collection, and support for concurrency.
- Popular users include Google, Docker, Dropbox, SoundCloud, and MongoDB. Domains it is used include distributed systems, cloud, web development, and systems programming.
- Key features include built-in concurrency and networking support, a rich standard library, and fast compilation. It aims to be
Celery is a Python-based distributed task queue that uses message queues like AMQP to asynchronously execute tasks across multiple machines. It provides features like task scheduling, retries, error handling, and integration with Django. Tasks are defined as Python functions decorated with the "@task" decorator. Workers process tasks from the queue and results are sent back via messages. Celery simplifies building asynchronous workflows in Python applications.
사내 발표자료 겸 만들었는데, ECS Fargate를 이용하실 분들이라면, 편리하게 쓰실 수 있도록 최대한 상세하게 만들어 보았습니다.
사실 CloudFormation 등 배포는 좀 더 편리하게 할 수 있지만, 회사 사정도 있고, 제가 일단 그런 기술을 너무 늦게 알았기 때문에 다루지는 않았습니다.
ONNX - The Lingua Franca of Deep LearningHagay Lupesko
ONNX aims to serve as a common intermediate representation (IR) format for neural network models to allow for interoperability across different frameworks and tools. It uses ProtocolBuffers for its binary format and defines operators and graphs. ONNX allows users to build models with one framework like PyTorch, export to ONNX, and load into another framework like MXNet for inference or further training. The MXNet Model Server also supports serving models in ONNX format.
Rest-assured is a 100% java-based, BDD style, test library that you can use for testing REST api's in java projects. These are the slides from the presentation and demo I give at the 2017 #JBCNConf Java conference in Barcelona.
Exploring Twitter's Finagle technology stack for microservices💡 Tomasz Kogut
This document summarizes a presentation about Finagle, Twitter's microservices technology stack. It discusses how Finagle addresses challenges with microservices like service discovery, load balancing, and request tracing across services. It presents Finagle's core abstractions like Futures, Services, and Filters. Services represent both clients and servers, and Filters can add functionality like retries and timeouts. The document also mentions Twitter Server, a framework for building Finagle-based servers that handles flags, logging, metrics and admin interfaces. Finally, it briefly introduces Finatra, which builds on Finagle and Twitter Server and adds features like dependency injection and routing.
The document discusses the Serverless Framework, which is a build tool that makes it easy to setup and invoke Lambda functions on AWS. It allows developers to manage multiple Lambda functions across different regions and stages, and share code between functions. The Serverless Framework supports Node.js, Python, Java/Scala and other runtimes. Functions are defined in a serverless.yml file along with triggers like HTTP events, S3 uploads, schedules and more. The framework handles deployments to AWS and other cloud providers.
This document provides an overview of the Go programming language. It discusses that Go was initially developed at Google in 2007 and is now an open source language used by many companies. The document then covers Why Go is useful, including its memory management, concurrency support, and cross-platform capabilities. It also summarizes some of Go's basic syntax like packages, functions, variables, types, and control structures. Finally, it discusses some key Go concepts like methods, interfaces, channels, and the net/http package.
Blockchain : Decentralized Application Development (Turkish)Cihan Özhan
www.cihanozhan.com
*It is the presentation of my blockchain event that I presented in 2019.
Teknopark Istanbul Announcement : https://www.teknoparkistanbul.com.tr/egitimler/blockchain-decentralized-uygulama-gelistirme-sunumu
AI Security : Machine Learning, Deep Learning and Computer Vision SecurityCihan Özhan
This document discusses technologies related to machine learning, deep learning, computer vision, and artificial intelligence. It covers topics such as ML/DL algorithms, applications, data objects, cloud computing services, distributed systems, security issues, model lifecycles, publishing ML projects, and adversarial attacks against various AI systems including image, speech, NLP, remote sensing, autonomous vehicles, and industrial applications. It also provides links to the founder's online profiles and contact information.
Python programlama diline şöyle hızlıca bir göz atmak için inceleyebilirsiniz.
Blog : http://www.cihanozhan.com
#python #programming #pythonprogramming #pythonprogramminglanguage #py #makineöğrenmesi #görüntüişleme #computervision #deeplearning #machinelearning #programminglanguages
Go Book - Fonksiyonlar, Metotlar, Arayüzler ve Yapılar
1. Fonksiyonlar, Metotlar, Arayüzler ve Yapılar
Bu bölümde programlama dünyasının en kritik parçalarından birkaçını inceleyeceğiz. İnceleyeceğimiz bu nesne
tipleri profesyonel ve modern yazılımlar geliştirmenin temel taşlarını oluşturmaktadır.
Fonksiyonlar
Yazılım geliştirirken kod tekrarı yapmamak dikkat edilmesi gereken en önemli unsurlardan biridir. Bu nedenle
belirli işler konusunda uzmanlaşmış nesneler üretmemiz gerekir.
Örneğin, geliştirilen uygulama içerisinde 10 satırlık bir matematik algoritmasını her seferinde tekrar yazmak
doğru bir yaklaşım mıdır? Hayır! Bu tür işlemlerin tek bir kez yazılması ve bu işlemin de sadece kendi işinde
uzmanlaştırılması gerekir.
İşte bu ihtiyaçlardan dolayı fonksiyon nesneleri doğmuştur. Biz her iş için ayrı ayrı fonksiyonlar geliştirir ve
bunları kullanırız.
Söz dizimi:
func fonksiyon-ad(parametre-listesi) (geri-donus-listesi) {
fonksiyon-govdesi
}
- Fonksiyon isimleri benzersiz olmalıdır.
- Fonksiyon parametre isimleri benzersiz olmalıdır.
- Bir fonksiyon geri dönüş değerlerine sahip olabilir ama bu zorunlu değildir.
- Fonksiyonun geri dönüş değeri birden fazla ise parantez kullanmak zorunludur.
- Geri dönüş tipine sahip bir fonksiyonun gövdesi return komutu ile bitmelidir.
Fonksiyon Tanımlamaları
Fonksiyonlar ile ilgili temel kural ve söz dizimini uygulamak için birkaç örnek yapalım
Örnek:
func topla(x int, y int) int { // isimsiz geri dönüş tipi
return x + y
}
Örneği kullanalım.
res := topla(5, 4)
fmt.Println(res)
Örnek çıktısı:
9
Dikkat: Eğer C# ya da Java gibi programlama dillerini kullandıysanız, Go dilindeki fonksiyonların parametre
tanımlaması size garip gelmiş olabilir. Çünkü diğer dillerde parametre tanımlarken önce veri tipi, sonra
parametre adı şeklinde bir parametre tanımı yapılırken, Go dilinde bu tam tersidir! Go dilinde önce parametrenin
cihanozhan.com
2. adını, sonra parametrenin veri tipini yazarız. Go dili tasarımcılarının bu konudaki beyanı: “Bu kullanım insan dili
ve düşünce tarzına daha yakın ve doğru olduğunu düşünüyoruz.”
topla isimli fonksiyonda geri dönüş veri tipi olarak integer’ı kullandık. Bu örnekte isimsiz geri dönüş yöntemini
kullandık. Ancak aşağıdaki şekilde isimlendirilmiş bir geri dönüş de kullanabiliriz.
func topla(x int, y int) (r int) { // isimlendirilmiş geri dönüş tipi
return x + y
}
Geri dönüş olarak r adını kullandık. Bu örneğin ilk örnekten bir diğer farkı ise geri dönüş tipinin parantez
içerisinde tanımlanmış olmasıdır. Eğer isimlendirilmiş bir geri dönüş nesnesi kullanıyorsak bunu parantez
içerisinde tanımlamak zorundayız. Aynı şekilde, eğer isimsiz olarak birden fazla geri dönüş değeri
tanımlayacaksak, bu değerleri gene parantez içerisinde tanımlamak zorundayız.
Örnek:
func topla(x int, y int) (int, int) { // Çoklu geri dönüş yapmak!
return 0, x + y // İlk geri dönüşteki 0 değeri sadece bir örnektir.
}
Fonksiyonların herhangi bir geri dönüş tipine sahip olma zorunluluğu yoktur. Bir fonksiyonu geri dönüş tipi
olmadan da aşağıdaki gibi tanımlayabiliriz.
Örnek:
func save(data float32) {
fmt.Println("Saved: ", data)
}
save() fonksiyonunu kullanalım.
save(4.5)
Örnek çıktısı:
Saved: 4.5
Sadece verilen görevi yerine getirmesi gereken ve herhangi bir geri dönüş değerine ihtiyaç duyulmayan
durumlarda, geri dönüş değeri olmayan fonksiyonlar tercih edilebilir.
Her türlü hesaplama ve iş kuralı için fonksiyonları kullanabiliriz. Örneğin, iki sayısal değer içerisinde en büyük
olanı bulalım.
Örnek:
func max(number1, number2 int) int {
var result int
if number1 > number2 {
result = number1
} else {
result = number2
}
return result
cihanozhan.com
3. }
Örnekteki max fonksiyonunu kullanalım.
var x, y = 30, 32
res := max(x, y)
fmt.Println("Sonuç: ", res)
Örnek çıktısı:
Sonuç: 32
Go diline özel diğer bir geri dönüş yöntemi ise naked return geri dönüş yöntemidir. Bu yöntem isimlendirilmiş
geri dönüş yöntemine benzemekle birlikte bu yöntemler birbirlerinden farklıdırlar.
Örnek:
func main() {
xx, yy := Increase(2, 4)
fmt.Println(xx)
fmt.Println(yy)
}
func Increase(x int, y int) (num1 int, num2 int) {
num1 = x + 1
num2 = y + 1
return
}
Örnek çıktısı:
3
5
Yukarıdaki naked return örneğine dikkat ederseniz return komutunun sonunda herhangi bir dönüş nesnesi
tanımlamadık. Bu yöntemin diğerlerinden temel farkı, return deyiminin herhangi belirli bir nesneyi
dönmemesidir. Bu fonksiyonun geri dönüş tiplerini tanımlarken belirttiğimiz num1 ve num2 nesneleri
fonksiyonun içerisinde kullanılabilir ve değeri değiştirilebilir nesnelerdir. Bu nesnelerle işimiz bittiğinde return
komutunu çalıştırarak bu nesnelerin geriye dönmesini sağlayabiliyoruz.
Yukarıdaki metodun geri dönüş tipini aşağıdaki gibi de tanımlayabilirdik;
func Increase(x int, y int) (num1, num2 int) {
…
}
Birinci Sınıf Fonksiyon Desteği
Birinci sınıf fonksiyonlar, fonksiyon nesnelerinin değişkenlere atanması, argümanlara parametre olarak
gönderilmesi ve bir fonksiyondan geri dönüş tipi olarak kullanılabilmesine denir. Go dili birinci sınıf
fonksiyonları destekler.
cihanozhan.com
4. Anonim Fonksiyonlar
Anonim değişkenler, belirli durumlarda ve sadece belirli işlemlerde geçerli olacak şekilde işleme özel hazırlanan
metotlardır.
Örnek:
func() {
fmt.Println("Merhaba Mars!")
}()
Örnek çıktısı:
Merhaba Mars!
Yukarıdaki kodu main() metodu içerisinde yazdık. Bu kod bir anonim fonksiyonun kullanımına verilebilecek en
temel örnektir. Anonim metotlar bu şekilde kendi başlarına çalışacak şekilde tanımlanabileceği gibi, bir
değişkene atanarak da kullanılabilirler.
Bir fonksiyonu değişkene atama işlemi için bir örnek yapalım.
Örnek:
x := func() {
fmt.Println("Merhaba Mars!")
}
x()
fmt.Printf("%T", x)
Örnek çıktısı:
Merhaba Mars!
Yukarıdaki örnekte, main() metodu içerisinde bir anonim fonksiyon tanımladık ve bu fonksiyonu x adıyla
oluşturduğumuz değişkene atadık. Bu atama işleminden sonra, artık x nesnesi bir fonksiyon gibi davranır. Ancak
bu durum bu fonksiyonun bir adı olduğu anlamına gelmez. Sadece bu fonksiyonu temsil edebilen bir nesne
olduğunu gösterir. Yani, halen bu fonksiyonun bir adı olmadığı için, bu yönteme anonim fonksiyon diyoruz.
Parametre Alan Anonim Fonksiyonlar
Bir anonim fonksiyonun parametreli olarak tanımlanması mümkündür. Bu için bir örnek yapalım.
Örnek:
func(p string) {
fmt.Println("Merhaba", p)
}("Mars!")
Örnek çıktısı:
Merhaba Mars!
Yukarıdaki örnekte, anonim fonksiyonu parametre alabilecek şekilde tasarladık ve parametrenin adını p, veri
tipini ise string olarak belirledik. Sonrasında, anonim fonksiyonun kapama parantezleri olarak kullandığımız
alanda ise “Mars!” metnini göndererek bu parametreyi fonksiyona sağlamış olduk.
cihanozhan.com
5. Tip Olarak Tanımlanan Anonim Fonksiyonlar
Bir anonim fonksiyonu type anahtar kelimesiyle bir tip olarak tanımlayabiliriz. Bu sayede, oluşturulan bu yeni
tipin parametrik yapısıyla aynı yapıya sahip fonksiyonlar için bir veri tipi olarak kullanılmasını sağlayabiliriz.
Örnek:
Aşağıdaki type tanımını main() metodunun üzerinde yapalım.
type fourMath func(p1 int, p2 int) int
fourMath adındaki bu type nesnesi bizim için bir şablon niteliği taşıyacak. Dışarıdan iki adet integer veri tipi
alan ve dışarıya bir adet integer veri tipinde veri göndermesi gereken bir fonksiyon şablonu. Bu fourMath isimli
type’ın amacı, matematikte kullandığımız temel 4 işlemi yapacak fonksiyonları temsil etmektir. Şimdi bu
şablonun gereksinimlerini karşılayacak bir fonksiyon oluşturalım.
// Toplama işlemini yapan fonksiyon
var add fourMath = func(x int, y int) int {
return x + y
}
// Çıkarma işlemini yapan fonksiyon
var sub fourMath = func(x int, y int) int {
return x - y
}
// Çarpma işlemini yapan fonksiyon
var multiply fourMath = func(x int, y int) int {
return x * y
}
// Bölme işlemini yapan fonksiyon
var div fourMath = func(x int, y int) int {
return x / y
}
// İşlemler
res_add := add(7, 6)
res_sub := sub(7, 6)
res_multiply := multiply(7, 6)
res_div := div(10, 2)
// İşlem sonuçları
fmt.Println("Sum", res_add)
fmt.Println("Sub", res_sub)
fmt.Println("Multiply", res_multiply)
fmt.Println("Div", res_div)
cihanozhan.com
6. Örnek çıktısı:
Sum 13
Sub 1
Multiply 42
Div 5
Fonksiyonlara Parametre Olarak Geçilen Anonim Fonksiyonlar
Anonim fonksiyonlar, teknik olarak bir veri tipi gibi yorumlanabildiği için bu fonksiyonları başka fonksiyonlara
bir parametre gibi gönderebiliriz.
Örnek:
f := func(x, y int) int {
return x + y
}
res := calculate(f)
fmt.Println(res)
calculate() fonksiyonunu hazırlayalım.
func calculate(param func(a, b int) int) int {
// Simülasyon : Çeşitli işlemler sonucunda 60 ve 7 değerlerini bulduk!
// Sonra bu değerleri param(...) fonksiyonuna gönderdik.
return param(60, 7)
}
Örnek çıktısı:
67
Bir Fonksiyondan Başka Bir Fonksiyonu Geri Dönmek
Bir fonksiyondan bu fonksiyon içerisinde oluşturulmuş farklı bir fonksiyonu geriye dönmek mümkündür.
Örnek:
func calculate() func(p1, p2 int) int {
f := func(p1, p2 int) int {
return p1 + p2
}
return f
}
Yukarıdaki yeni calculate() fonksiyonunu kullanalım.
res := calculate()
fmt.Println("result: ", res(83, 8))
Örnek çıktısı:
result: 91
cihanozhan.com
7. calculate() fonksiyonunun yeni halinin biraz açıklamaya ihtiyacı olabilir.
Yukarıda tanımladığımız calculate() fonksiyonu herhangi bir parametre almıyor. Ancak geriye farklı bir
fonksiyon yapısı dönmektedir. Geriye dönülen bu fonksiyon, dışarıdan p1 ve p2 adında iki adet integer
parametre alır. calculate() içerisinde oluşturduğumuz yeni bir isimsiz fonksiyon da dış fonksiyondan alınan p1
ve p2 parametrelerini parametre olarak almaktadır. İçerideki isimsiz fonksiyonda ise, sadece basit bir şekilde
dışarıdan gelen parametrelerin toplama işlemi yapılmaktadır. Tüm bu işlemlerin sonunda geriye bir fonksiyon
dönmek için, isimsiz fonksiyonu atadığımız f adındaki nesneyi return ile geriye dönüyoruz.
Closure
Şu ana kadar fonksiyonlara parametre göndererek onları kullanmayı inceledik. Mevcut genel parametre
kullanımının yaklaşımı değer tipi olarak çalışmak üzerine kuruludur.
Hatırlatma : Değer tipleri hafızada kopyalanarak aktarılırlar. Bu nedenle, normal bir fonksiyon kullanımında
parametre olarak gönderilen değişken ile fonksiyonun parametre olarak aldığı değişken bilgisayar hafızasında
farklı adreslere sahiptir. Yani ikisi birbirinin kopyası olsa da farklı nesnelerdir.
Ancak, istersek bir fonksiyona parametre olarak gönderilecek değişkenlerin bir parametre olarak değil, doğrudan
fonksiyon içerisinde tanınarak kullanılmasını sağlayabiliriz. Biraz karışık gibi görünebilir. Ancak gayet basittir.
Şimdi bir fonksiyonu nasıl bir closure olarak kullanabileceğimize bir bakalım.
Örnek:
Uygulamamızın main() fonksiyonu içerisinde aşağıdaki anonim fonksiyonu tanımlayarak kullanalım.
x := 5
func() {
fmt.Println("x =", x)
}()
Örnek çıktısı:
x = 5
Hatırlarsanız bir anonim fonksiyona parametre gönderebiliyorduk. Ancak yukarıdaki örneğe dikkat ederseniz, bu
anonim fonksiyona herhangi bir parametre göndermediğimiz halde, dışarıda tanımlanan x değişkenine anonim
fonksiyonun referansına anonim fonksiyonun içerisinden ulaşarak kullanabildik.
Not : C# programlama dili kullananlar için, Go dilindeki closure yaklaşımı C#’daki ref ve out parametreleriyle
benzer amaçlar için dil tasarımına eklenmiştir.
Closure bir anonim fonksiyon yaklaşımıdır. Yani aslında closure fonksiyonları da birer anonim fonksiyonlardır.
Ancak closure fonksiyonlarının normal fonksiyonlardan farkı, bir değişkeni parametre olarak gönderip değer
tipi(value type) olarak davranmasını beklemek yerine, bir referans tipi olarak kullanılmasını sağlamaktır. Bu
sayede değişkenlerin hafızadaki adreslerini referans olarak closure içerisinden erişilebilmesini sağlar.
Örnek:
x := 0
counter := func() int {
x++
return x
}
cihanozhan.com
8. fmt.Println(counter())
fmt.Println(counter())
Örnek çıktısı:
1
2
Yukarıda closure yapısını basit bir şekilde anlatan başka bir örnek daha yaptık. Basit bir sayaç fonksiyonu
tanımlamak için closure tanımladık. Bu closure fonksiyonu bir üst satırdaki x değişkeninin referansına
erişebildiği için içeride x’in değerini her seferinde bir artırabiliyoruz. Artırma işleminden sonra ise, bu değişkeni
closure’dan geri dönüyoruz.
Closure fonksiyonların bir diğer faydası da veri izolasyonu(data isolation) sağlamasıdır. Örneğin, yukarıdaki
kodu main() fonksiyonu içerisinde yazdık. Bu demek oluyor ki, main() metodu içerisinden x değişkenine
erişerek closure’daki işleme dışarıdan müdahale edilebilir. Bu tür, kod ya da veriye kendi işlemi dışından
müdahale edilebilmesine engel olma işlemine veri izolasyonu diyoruz.
Örnek:
// counterProcess adında yeni bir closure fonksiyon tanımlayalım.
func counterProcess() func() int {
x := 0
return func() int {
x++
return x
}
}
// counterProcess fonksiyonunu main() fonksiyonu içerisinde kullanalım.
counter := counterProcess()
fmt.Println(counter())
fmt.Println(counter())
Örnek çıktısı:
1
2
Aslında son örneğimizde bir önceki örneğin aynısını yaptık. Ancak bu sefer closure’ı fonksiyon dönen bir
fonksiyon içerisinde tanımladık. Bu sayede, artık closure içerisinde referansı kullanılan x değişkenine dışarıdan
müdahale edilmesini engelledik.
Şimdi de closure için farklı bir gerçek dünya uygulaması yapalım.
Örnek:
// append() adında fonksiyon dönen yeni bir fonksiyon tanımlıyoruz.
func append() func(string) string {
str := ""
co := func(x string) string {
str = str + " " + x
return str
cihanozhan.com
9. }
return co
}
// main() fonksiyonu içinde append() fonksiyonu kullanıyoruz.
app := append()
app("Hello")
app("Gophers")
result := app("!")
fmt.Println(result)
Örnek çıktısı:
Hello Gophers !
Yukarıdaki örnekte dışarıdan aldığı metinsel veriyi kendi içindeki metinsel veri ile birleştirerek uç uca ekleyen
append() adında bir closure fonksiyon tanımladık. Bu fonksiyonu kullanırken de, app adında bir değişkenine
append() fonksiyonunu atayarak app değişkeninin append() fonksiyonu gibi davranmasını sağladık. Sonrasında
ise, app() fonksiyonuna sürekli yeni metinsel veriler ekleyerek hepsini uç uca birleştirmesini sağladık. En son
işlemde de app() fonksiyonundan dönen birleştirilmiş metinsel veriyi result adındaki değişkene atayarak ekrana
bastık.
Şu ana kadar birçok örnek yaptık. Ancak bu kitabın temel özelliği, Go dilini hem öğretmek, hem de uygulamalar
yaparak bu özelliklerin nasıl uygulandığını örneklerle göstermektir. Bu nedenle, şimdi closure fonksiyonlarını ve
struct yapısını kullanarak biraz daha detaylı bir gerçek dünya uygulaması yapalım.
Uygulama Amacı: Bir teknoloji firmasının çalışan bilgilerini ve uzmanlık alanlarını tutacak ve bu veriler
üzerinde çeşitli filtre ve hesaplamalar yapacak mini bir uygulama geliştirmek.
Uygulama:
Uygulamanın genel struct yapısını oluşturalım.
type Employee struct {
FirstName string
LastName string
Salary int
Expertises []Expertise
}
type Expertise struct {
ID int
Name string
}
Uygulama içerisinde kullanacağımız struct nesnelerini tanımladık. Her bir çalışanın birden fazla uzmanlık alanı
olabileceği için ilgi alanlarını(Expertises) dizi olarak tutuyoruz.
Uygulamanın fonksiyonlarını hazırlayalım.
// Çok amaçlı filtreleme fonksiyonudur.
func filter(emps []Employee, f func(Employee) bool) []Employee {
var empList []Employee
cihanozhan.com
10. for _, emp := range emps {
if f(emp) == true {
empList = append(empList, emp)
}
}
return empList
}
// Sadece sayaç görevi için kullanılacak fonksiyondur.
func count(emps []Employee, f func(Employee) bool) int {
var count int
for _, emp := range emps {
if f(emp) == true {
count++
}
}
return count
}
Uygulama içerisinde kullanacağımız genel fonksiyonlarımızı da hazırladık. Ancak bu uygulama için demo
verilere ihtiyacımız olacak! Demo verileri de bilgisayar hafızası üzerinde çalışacak şekilde ayrı bir fonksiyon
olarak hazırlayacağız.
func getData() []Employee {
var val = make([]Employee, 0, 0)
v1 := Employee{
FirstName: "Cihan",
LastName: "Özhan",
Salary: 1100,
Expertises: []Expertise{
Expertise{3, "C#"},
Expertise{5, "Go"},
Expertise{6, "Oracle"},
Expertise{8, "PostgreSQL"},
Expertise{10, "SQL Server"},
},
}
v2 := Employee{
FirstName: "Murtaza",
LastName: "Çalışkan",
Salary: 986,
Expertises: []Expertise{
Expertise{4, "HTML"},
Expertise{7, "JavaScript"},
Expertise{10, "SQL Server"},
},
}
val = append(val, v1)
val = append(val, v2)
cihanozhan.com
11. return val
}
Yukarıdaki getData() fonksiyonunu sadece uygulama içerisinden veriye erişim için kullanacağız.
Artık main() fonksiyonu içerisinde çalışmaya başlayabiliriz.
Öncelikle, aşağıdaki komutu kullanarak uygulamamızın hafızasına demo verileri dolduracağız.
empList := getData()
// Maaşı 1000 birim üzerinde olan çalışanları getir.
searchTagSalary := 1000
f1 := filter(empList, func(emp Employee) bool {
if emp.Salary >= searchTagSalary {
return true
}
return false
})
fmt.Println(f1)
f1 çıktısı:
[{Cihan Özhan 1100 [{3 C#}{5 Go}{6 Oracle}{8 PostgreSQL}{10 SQL Server}]}]
empList := getData()
// Adı "Murtaza" olan çalışanları getir.
searchTagName := "Murtaza"
f2 := filter(empList, func(emp Employee) bool {
if emp.FirstName == searchTagName {
return true
}
return false
})
fmt.Println(f2)
f2 çıktısı:
[{Murtaza Çalışkan 986 [{4 HTML} {7 JavaScript} {10 SQL Server}]}]
empList := getData()
// HTML uzmanlık alanına sahip çalışanları getir.
searchTagExpertise := "HTML"
f3 := filter(empList, func(emp Employee) bool {
for i := 0; i < len(empList); i++ {
if emp.Expertises[i].Name == searchTagExpertise {
return true
}
}
return false
})
fmt.Println(f3)
cihanozhan.com
12. f3 çıktısı:
[{Murtaza Çalışkan 986 [{4 HTML} {7 JavaScript} {10 SQL Server}]}]
// 1000 birim ve üzeri maaş alan çalışanları getir. (500 değeriyle de deneyiniz!)
searchTagSalaryForCount := 1000
f4 := count(empList, func(emp Employee) bool {
if emp.Salary >= searchTagSalaryForCount {
return true
}
return false
})
fmt.Println(f4)
f4 çıktısı:
1
Yukarıdaki her bir f değişkeni(f1, f2, f3, f4) ayrı bir işlemin sonucunu tutmaktadır. Bunları ayrı ayrı ekrana
basarak inceleyiniz.
Bonus olarak bu mini uygulama üzerinde aşağıdaki işlemleri de yapabilirsiniz.
Örnek : Çalışanların ad ve soyadlarını birleştirerek ekrana yazdıralım.
for _, v := range getData() {
fmt.Println(v.FirstName + " " + v.LastName)
}
Örnek çıktısı:
Cihan Özhan
Murtaza Çalışkan
Örnek : Tüm çalışanların uzmanlık alanlarını ekrana yazdıralım.
for _, v := range getData() {
for _, e := range v.Expertises {
fmt.Println(strconv.Itoa(e.ID) + " " + e.Name)
}
fmt.Printf("n")
}
Not : Yukarıdaki örnekte strconv built-in paketi kullanılmıştır.
Örnek çıktısı:
3 C#
5 Go
6 Oracle
8 PostgreSQL
10 SQL Server
cihanozhan.com
13. 4 HTML
7 JavaScript
10 SQL Server
Ertelenmiş Fonksiyonlar: Defer
Defer ile tanımlanan fonksiyonlar, kendisini çevreleyen fonksiyon geri dönüş işlemine gelene kadar ertelenen
fonksiyonlardır.
Ertelenmiş bir fonksiyon çağrısının argümanları anında değerlendirilir. Ancak fonksiyon çağrısı kendisini
çevreleyen fonksiyon dönmeden işleme alınmaz.
Bir veritabanı işlemi yaptığımızı düşünelim. Bir veritabanı işlemi yapmanın temel kuralı, veritabanı üzerinde bir
bağlantı açmaktır. Bağlantı açma işleminden sonra gerekli SQL sorguları yapılır ve tüm işlemler bittikten sonra
da veritabanı bağlantısı kapatılmalıdır.
Bu senaryoya göre nasıl bir defer kullanımı yapabileceğimize bir bakalım.
Örnek:
main() fonksiyonu üzerinde isConnected adında bir değişken tanımlayalım.
var isConnected bool = false
Sonrasında bu mini uygulamada kullanmak için paket seviyesindeki temel fonksiyonları hazırlayalım.
func databaseProcessing() {
connect()
fmt.Println("Bağlantıyı kesme işlemi erteleniyor!")
defer disconnect()
fmt.Printf("Bağlantı açık: %vn", isConnected)
fmt.Println("Veritabanı işlemleri yapılıyor!")
}
func connect() {
isConnected = true
fmt.Println("Veritabanına bağlıyız!")
}
func disconnect() {
isConnected = false
fmt.Println("Veritabanı bağlantısı kapalı!")
}
Uygulamanın main() fonksiyonu içerisindeki işlemleri yapalım.
fmt.Printf("Bağlantı açık: %vn", isConnected)
databaseProcessing()
fmt.Printf("Bağlantı açık: %vn", isConnected)
Örnek çıktısı:
cihanozhan.com
14. Bağlantı açık: false
Veritabanına bağlıyız!
Bağlantıyı kesme işlemi erteleniyor!
Bağlantı açık: true
Veritabanı işlemleri yapılıyor!
Veritabanı bağlantısı kapalı!
Bağlantı açık: false
Yukarıdaki uygulamada neler oldu?
Öncelikle mevcut veritabanı bağlantısının açık olup olmadığını kontrol ettik. Veritabanı bağlantısını henüz
açmadığımız için bağlantının kapalı olduğuna dair false bilgisini aldık. Sonrasında ise databaseProcessing()
fonksiyonunu çalıştırdık. Bu fonksiyon içerisinde ilk olarak connect() fonksiyonu çalıştırılmaktadır. Bu
fonksiyon ise veritabanı bağlantısını açmak için kullanılmaktadır. Ve bu nedenle, ekranda Veritabanına
bağlıyız mesajını gördük. Hemen connect() işleminden sonra ise defer ile birlikte disconnect() fonksiyonunu
çağırdık! İşte bu nokta önemli… Aslında biz o anda veritabanı bağlantısını sonlandırmak istemiyoruz. Sadece
Go derleyicisine söylemek istediğimiz şudur: “Bu fonksiyon içerisinde veritabanı ağlantısı açıldıktan sonra
veritabanı üzerinde birçok işlem yapacağım. Bu işlemler bittikten sonra(fonksiyonun sonunda) mevcut
açık olan veritabanı bağlantısını otomatik olarak kapat”. İşte bu nedenle disconnect() fonksiyonunu tüm
işlemlerden önce defer ile birlikte çağırabiliyoruz.
Not : Veritabanı ya da stream işlemlerinde kaynaklar üzerinde oluşturulan bağlantıların yönetilmesi ve işlem
bittikten sonra kapatılması bazen unutulabilmektedir. Bu durum sistem kaynaklarının tüketimini olumsuz yönde
etkiler. Bu tür durumlarla karşılaşmamak için defer kullanımını alışkanlık haline getirmek işinizi
kolaylaştırabilir.
Metotlar
Metotlar temel anlamda birer fonksiyondur. Metotların fonksiyonlardan temel farkı, metotların sadece
parametrelerinin değil, aynı zamanda alıcılarının da olmasıdır.
Söz dizimi:
func (t Type) methodName(parameter-list) {
}
Yukarıdaki metot söz diziminde fonksiyonlardan farklı olarak dikkatleri çeken nokta (t Type) şeklinde
kullanılan tanım alanıdır. Bu alan metodun hangi alıcı tipiyle çalışacağının belirtildiği alandır. Bir metoda alıcı
olarak atanan nesne çalışma anında bu metot ile aynı scope içerisinde çalıştırılır.
Not : C# ya da Java gibi programlama dillerinde bu yaklaşım bulunmaz. Bunun nedeni bu dillerin metotları
kendi class’ları içerisinde tanımlamaya zorlamasıdır. Ancak Go dilinde struct(class yerine) için özel olarak
belirlenen bir scope parantezi yer almaz. Bu nedenle, Go dilinde bir metodu bir nesneye bağlamak için o
nesnenin tipini ilgili metoda alıcı olarak bağlamamız gerekir. Bu diğerlerine göre daha sade ve kullanışlı bir
yöntemdir.
Metotları genel olarak struct nesneleriyle birlikte kullanacak olsak da, bir metodu herhangi bir Go tipiyle
birlikte kullanabiliriz.
Şimdi integer veri tipine sahip özel bir tip oluşturalım ve bu tipe MultipleBy10 adında yeni bir metot atayarak
kullanalım.
cihanozhan.com
15. Örnek:
type MyInt int
func (x MyInt) MultiplyBy10() int {
if x <= 0 {
return int(x)
}
return int(x) * 10
}
Örneğin kullanımı:
val := MyInt(10)
fmt.Println(val.MultiplyBy10())
Örneğin çıktısı:
100
Yukarıdaki örnekte MyInt adında arka planda integer tipine sahip özel bir tip kullandık. Bu tür kullanımları
uygulamalarda bolca kullanmak gerekse de, metotların en yaygın kullanılacağı nesne tipi struct’dır.
Şimdi en temel haliyle bir metodun struct nesnesiyle nasıl kullanılacağına bir bakalım.
Örnek:
type T struct {
name string
}
func (x T) PrintName() {
fmt.Println(x.name)
}
Yukarıdaki örneği main() fonksiyonu içerisinde kullanalım.
t := T{name: "Cihan"}
t.PrintName()
Örnek çıktısı:
Cihan
Bir metodun struct ya da diğer tipler ile kullanımı arasında herhangi bir fark yoktur. Hazırladığımız metot,
kendisine alıcı olarak atadığımız tipe ait bir metot olarak çalışmak üzere tasarlanmıştır.
Metotlar konusunda daha birçok örnek yapabiliriz. Ancak kitap içerisinde metot nesnelerini sık sık kullanacağız.
Bu nedenle, metotlar bölümünde özellikle metotları bir uygulama ile açıklamak daha faydalı olabilir.
cihanozhan.com
16. Örnek:
Bu örnekte, gerçek bir uygulama geliştirirken karşılaşabileceğimiz bir senaryoyu uygulayacağız. Elimizde
kullanıcı ve bu kullanıcılara ait ilgi alanlarıyla birlikte, her kullanıcının sistem üzerinden elde ettiği kazanç gibi
veriler mevcut. Bu kullanıcı verisini metot yapısına uygun şekilde kullanacağız.
Not : Bu uygulama örneğinde fmt ve time paketlerini kullanacağız.
Kullanıcı verisini tutacak User nesnesinden önce, bu nesne ile ilişkili olacak alt struct nesnelerini oluşturalım.
Kullanıcının kazanç bilgilerinin özetini tutmak için RevenueSummary struct’ı:
type RevenueSummary struct {
ID int
TotalRevenue float64
TotalSales int
}
Kullanıcının ilgi alanlarını tutmak için Interest struct’ı:
type Interest struct {
ID int
Name string
}
Kullanıcının temel bilgilerini tutmak için User struct’ı:
type User struct {
ID int
FirstName string
LastName string
UserName string
DoB string
RevenueSummary *RevenueSummary
Interests []Interest
}
Uygulamanın temel struct yapısı hazır. Şimdi uygulamanın çalışması için gereken metotları hazırlayabiliriz.
Kullanıcının ad ve soyad bilgilerini birleştirerek getiren GetFullName() metodu:
func (u User) GetFullName() string {
return u.FirstName + " " + u.LastName
}
Kullanıcının kullanıcı adı bilgisini getiren GetUserName() metodu:
func (u *User) GetUserName() string {
return u.UserName
}
Kullanıcının gelir özet verisini bir RevenueSummary struct’ı olarak getirecek GetRevenueSummary()
metodu:
cihanozhan.com
17. func (u *User) GetRevenueSummary() RevenueSummary {
return *u.RevenueSummary
}
Kullanıcının doğum tarihine göre yaşını hesaplayarak getirecek GetAge() metodu:
func (u *User) GetAge() int {
t, _ := time.Parse("2006-01-02", u.DoB)
age := time.Now().Year() - t.Year()
return age
}
Kullanıcının ilgi alanlarını bir Interest struct listesi olarak getirecek GetInterests() metodu:
func (u *User) GetInterests() []Interest {
return u.Interests
}
Kullanıcının ilgi alanlarının toplamını hesaplayarak getirecek GetCountOfInterests() metodu:
func (u *User) GetCountOfInterests() int {
return len(u.Interests)
}
Uygulama için gerekli tüm nesneler hazır. Şuan tek eksiğimiz uygulama içerisinde kullanacağımız örnek bir
kullanıcı verisini tutan demo veri yapısıdır. Bunun için de getData() adında ayrı bir fonksiyon tanımlayacağız.
func getData() User {
user := &User{
ID: 1,
FirstName: "Cihan",
LastName: "Özhan",
UserName: "CihanOzhan",
DoB: "1988-01-09",
RevenueSummary: &RevenueSummary{
TotalRevenue: 5300,
TotalSales: 54,
},
Interests: []Interest{
Interest{2, "Databases"},
Interest{5, "Web Programming"},
},
}
return *user
}
Not : getData() nesnesi bir metot değil fonksiyondur.
Artık main() fonksiyonuna geçerek bu nesneleri kullanabiliriz.
// Örnek kullanıcı verisini u adındaki değişkene atayalım.
cihanozhan.com
18. u := getData()
fmt.Println("Temel Bilgiler:")
fmt.Println("-> Kullanıcının Tam Adı: ", u.GetFullName())
fmt.Println("-> Kullanıcı Adı: ", u.GetUserName())
fmt.Println("-> Yaş: ", strconv.Itoa(u.GetAge())+"n")
fmt.Println("İlgi Alanları: ")
for _, v := range u.GetInterests() {
fmt.Println("--> İlgi Alanı: ", v.Name)
}
countOfInterests := strconv.Itoa(u.GetCountOfInterests())
str := u.FirstName + "'ın İlgi Alanlarının Toplamı: " + countOfInterests
fmt.Println(countAllStr + "n")
fmt.Println("Kazanç Bilgileri:")
totalRev := u.GetRevenueSummary()
fmt.Println("-> Toplam Kazanç: ", totalRev.TotalRevenue)
fmt.Println("-> Toplam Satış Adedi: ", totalRev.TotalSales)
Örnek çıktısı:
Temel Bilgiler:
-> Kullanıcının Tam Adı: Cihan Özhan
-> Kullanıcı Adı: CihanOzhan
-> Yaş: 30
İlgi Alanları:
--> İlgi Alanı: Databases
--> İlgi Alanı: Web Programming
Cihan'ın İlgi Alanlarının Toplamı: 2
Kazanç Bilgileri:
-> Toplam Kazanç: 5300
-> Toplam Satış Adedi: 54
Bir konuya dikkatinizi çekmek istiyorum! GetFullName() metodundaki alıcı tanımlama alanında işaretçi(*)
simgesini kullanmadım. Ancak diğer tüm metotlarda alıcı olarak işaretçi kullandım. Muhtemelen bu konu
dikkatli okuyucuların gözüne çarpmıştır. Şimdi bir metot alıcısı olarak işaretçi kullanıp kullanmama konusunu
inceleyelim.
Metot Alıcısı Olarak İşaretçi Kullanımı
İşaretçiler için küçük bir hatırlatma yapalım. İşaretçiler doğrudan nesne örneğinin hafızadaki adresini temsil
ederler. Bu nedenle, eğer bir işaretçi üzerinde işlem yaparsanız, bu işaretçi hangi nesne örneği tarafından temsil
edilirse edilsin, orijinal veri üzerinde değişiklik yapacaktır.
Metotlar ile işaretçi kullanımını incelemek için önceki uygulamaya bir ekleme yapacağız. Bu eklemeyi
kullanıcının adını değiştirmek amacıyla SetUserName(…) metodu ile yapacağız.
Örnek: İşaretçisiz kullanım
func (u User) SetUserName(uName string) {
u.UserName = uName
}
cihanozhan.com
19. Oluşturduğumuz bu yeni metodu kullanalım:
u.SetUserName("CO")
fmt.Println(u.GetUserName())
Örnek çıktısı:
CihanOzhan
Kullanıcı adını değiştirme metodunu kullandık ancak kullanıcı adımız değişmedi! Bu durum, bizim gerçek
anlamda o anki kullanıcının kopyası üzerinde bu işlemi yapmamış olmamızdan kaynaklanmaktadır. Eğer o anki
nesne örneğinde bulunan kullanıcı üzerinde bu işlemin yapılmasını istiyorsak, işaretçi ile tanımlı alıcı
kullanmalıyız.
Şimdi SetUserName(..) fonksiyonunu işaretçi alıcısı alacak şekilde yeniden düzenleyip örneği tekrar
inceleyelim.
Örnek: İşaretçi kullanımı
func (u *User) SetUserName(uName string) {
u.UserName = uName
}
Oluşturduğumuz bu yeni metodu kullanalım:
u.SetUserName("CO")
fmt.Println(u.GetUserName())
Örnek çıktısı:
CO
Go ile uygulama geliştirirken en sık kullanılacak nesnelerden biri işaretçilerdir. Bu nedenle struct ile işaretçilerin
nasıl çalıştığını doğru şekilde anlamak gerekmektedir. Eğer metodun alıcısı olduğu nesnenin örneği üzerinde bir
değişiklik yapmak isterseniz işaretçi kullanmalısınız.
cihanozhan.com
20. Arayüzler
…
Yapılar
Bu bölümde, Go dilinin mevcut programlama dillerinden farklı olan bir bakış açısını daha inceleyeceğiz. Şu ana
kadar kullandığımız programlama dillerinin çoğunda kullanılan temel bir özellik vardı: class(sınıf)
Nesne modelleri oluşturmak için kullandığımız class kavramı Go dilinde bulunmaz. Onun yerine, aynı amaç için
tasarlanan struct(yapı) kullanılır. Yapılar, kullanıcı tanımlı tiplerdir ve genellikle yapısı belli olan(olmayabilir
de) verileri nesnel ortamda temsil etmek için çeşitli field(alan)’lardan oluşan nesnelerdir. Go dilinde
kullandığımız struct(yapı) yapısının diğer dillerdeki class yapılarından bazı farklılıkları da vardır. Şimdi yapı
nesnelerinin tüm özelliklerini detaylıca inceleyelim.
Not : Yapı nesnesi Go ile profesyonel uygulamalar geliştirmek için kullanılan en temel özelliklerden biridir. Bu
nedenle, yapıların kullanımları ve detayları üzerine birçok uygulama çalışması yapacağız.
Not : struct nesnesinin Türkçe’deki karşılığı yapı’dır.
Yapı Tanımlamak ve İlklendirmek
Yeni bir yapı tanımlamak için type anahtar kelimesini kullanıyoruz. En temel haliyle bir yapı aşağıdaki gibi
tanımlanabilir:
Örnek:
type Article struct {
id int
title string
content string
resourceURL string
authorID int
categoryID int
}
Yukarıdaki yapı modelinde bir makale yapısını programatik olarak tasarladık. Herhangi bir makalenin veritabanı
işlemlerini gerçekleştirmek ve makale verilerini uygulamanın hafızasında anlamlı şekilde yönetebilmek için
böyle bir yapıya ihtiyacımız vardı.
Aynı veri tiplerine sahip yapı alanlarını tek satırda da tanımlayabiliriz:
Örnek:
type Article struct {
id, authorID, categoryID int
title, content, resourceURL string
}
Not : Tek satırda yapı alanları tanımlama yöntemini uygularken dikkatli olunmalıdır! Bu kullanımın amacı, kod
kalabalığını azaltmaktır. Ancak, çok fazla alana(field) sahip yapılarda her veri tipine düşen alan adedinin fazla
cihanozhan.com
21. olması nedeniyle, kodun okunabilirliği azalabilir. Bu tür durumlardan kaçınmak için, yazılım geliştirme
standartlarına uyulmalı ve kendi uygulama kurallarınızı oluşturarak bunlara bağlı kalmalısınız.
Peki bir yapının başlangıç(sıfır) değeri nedir?
Bir yapının nesne örneğini oluşturduğumuzda yapıya ait alanların da hafıza üzerinde nesne kurulumları yapılır.
Yapıya ait nesne alanları kendi tiplerinin başlangıç değerlerine(sıfır değeri) sahip olurlar.
Örnek:
var art3 Article // sıfır değeri oluşturulmuş nesne
fmt.Println("art3", art3)
Örnek çıktısı:
art3 {0 0 0}
Yukarıdaki sonuçta görüldüğü üzere, integer bir alanın başlangıç değeri sıfır(0), string alanın ise boşluk olarak
tanımlanır. Aynı durum diğer veri tipleri için de geçerlidir.
Eğer oluşturduğumuz art3 nesne örneğinin metinsel alanlarına veri girişi yaparsak, integer alanların başlangıç
değerleri korunmakla birlikte, metinsel alanlarda yeni girilen veriler tutulacaktır.
Örnek:
var art3 Article // sıfır değeri oluşturulmuş nesne
art3.content = "Bir makale içeriği."
art3.resourceURL = www.cihanozhan.com
fmt.Println("Article 3", art3)
Örnek çıktısı:
Article 3 {0 Bir makale içeriği. www.cihanozhan.com 0 0}
Nesne ilklendirme ve başlangıç değerlerini incelediğimize göre, artık başlangıç değerleri atayarak nesne örneği
oluşturmak için birkaç örnek inceleyebiliriz.
Örnek:
// Alan isimlerini kullanarak yapı ilklendirmek
art1 := Article{
title: "Go ile XML Veriyi JSON'a Dönüştürme",
content: "Bu örneğimizde bir XML formatlı veriyi JSON …",
resourceURL: "cihanozhan.com/go-ile-xml-veriyi-jsona-donusturme/",
authorID: 7,
categoryID: 9,
}
// Alan isimlerini kullanmadan yapı ilklendirmek
art2 := Article{
0, // id alanı!
"Go ile Şifreleme İşlemleri",
"Bu makalede Go işe şifreleme yapmayı ve ilgili paketleri …",
"cihanozhan.com/category/golang/",
cihanozhan.com
22. 7,
9,
}
Article isimli yapının art1 nesne örneğinde kullandığımız yöntem Go topluluğu tarafından en çok tercih
edilen yöntemdir. Ancak bazı durumlarda daha pratik ve isimlendirme gerekmeyen kullanım yöntemini
kullanmak gerekebilir. Bu durumda da art2 nesne örneğinin yöntemi uygulanabilir. art2’de dikkat ederseniz, id
alanını da göndermek zorunda kaldık! Bu kullanım yönteminde herhangi bir alan adı vermediğimiz için tüm
alanları göndermek zorundayız. Aksi halde, Go derleyicisi hangi verinin hangi alana ait olduğunu
anlayamayacağı için hata verecektir.
Uygulamanın çıktısını görmek için:
fmt.Println("Makale 1: ", art1)
fmt.Println("Makale 2: ", art2)
Bir Yapının Alanlarına Erişmek
Bir yapıya ait alanlara erişmek için nokta(.) operatörü kullanılır. Bu konuyu örneklendirmek için daha önce
oluşturduğumuz art1 isimli Article nesne örneğini kullanacağız.
Örnek:
art1 := Article{
title: "Go ile XML Veriyi JSON'a Dönüştürme",
content: "Bu örneğimizde bir XML formatlı veriyi JSON …",
resourceURL: "cihanozhan.com/go-ile-xml-veriyi-jsona-donusturme/",
authorID: 7,
categoryID: 9,
}
fmt.Println("ID: ", art1.id)
fmt.Println("Title: ", art1.title)
fmt.Println("Content: ", art1.content)
fmt.Println("Resource: ", art1.resourceURL)
fmt.Println("AuthorID: ", art1.authorID)
fmt.Println("CategoryID: ", art1.categoryID)
Örnek çıktısı:
ID: 0
Title: Go ile XML Veriyi JSON'a Dönüştürme
Content: Bu örneğimizde bir XML formatlı veriyi JSON …
Resource: http://www.cihanozhan.com/go-ile-xml-veriyi-jsona-donusturme/
AuthorID: 7
CategoryID: 9
Şu ana kadar oluşturduğumuz Article örneğindeki yapıya named structure(isimlendirilmiş yapı) diyoruz. Bir
diğer yapı oluşturma yöntemiyse anonymous struct(anonim yapı) yaklaşımıdır. Şimdi ona bakalım…
cihanozhan.com
23. Yapılarda Erişim Belirleyicileri
Eğer C# ya da Java programlama gibi bir tecrübeniz var ise, bu dillerdeki erişim belirleyicilerine(public, private,
protected vb.) dokunmadan orta ya da büyük çaplı bir proje tasarlayamayacağınızı biliyor olmalısınız. Bu tür
tanımlamalar, ilgili nesnenin erişim sınırlarını belirler.
Peki, bir Go paketi içerisinde tanımladığımız herhangi bir nesnenin o paketin dışından erişilebilir olup
olmadığını nasıl kontrol edeceğiz?
Go dili herhangi bir erişim tanımlayıcı anahtar kelime(public, private vb.) kullanmaz. Go derleyicisi sadece
nesnenin baş harfinin büyük ya da küçük olma durumuna göre erişimleri belirler.
- Go paketinde tanımladığınız nesnenin baş harfi büyük ise bu nesneye paketin dışından erişilebilir.
- Go paketinde tanımladığınız nesnenin baş harfi küçük ise bu nesneye paketin dışından erişilemez.
Go dilinin erişim belirleme kuralı sadece aşağıdaki nesneler için değil, paket içerisindeki tüm nesneler için
geçerlidir. Aşağıdakiler sadece örnektir.
Değişken:
- Public :
o var Age int
- private :
o var age int
Yapı:
- Public :
o type User struct { }
- private :
o type user struct { }
Metot:
- Public:
o func IsValid() bool
- private :
o func isValid() bool
Bu kurala göre, eğer oluşturduğunuz bir yapı nesnesinin paket dışından erişilebilir olmasını istiyorsanız, yapı
nesnesinin adı büyük harfle başmalıdır. Aynı şekilde, eğer bir yapı nesnesinin içindeki alanların dışarıdan
erişilebilir olmasını istiyorsanız, bu alanların da baş harfi büyük harfle başlamalıdır.
Anonim Yapı Tanımlamak ve İlklendirmek
Article isimli yapı nesnesinden görüldüğü üzere yeni yapı tanımlama işlemlerinde type anahtar kelimesini
kullanıyoruz. Ancak var ile de değişken tanımlar gibi yeni bir yapı tanımlaması yapabiliriz. Bu yaklaşıma da
anonim yapı(anonymous structure) diyoruz.
Örnek:
var article struct {
id, authorID, categoryID int
title, content string
}
cihanozhan.com
24. Yapı ile Pointer Kullanımı
Pointer kullanımı ile ilgili bölümde Go dilindeki işaretçi yapısını ve kullanımını örneklemiştik. Birçok
programlama dilinin aksine, Go dilinde işaretçilerin kullanımı çok yaygındır. Go dilinde işaretçiler özellikle yapı
ve metot/fonksiyon gibi nesnelerde çok sık kullanılır.
Şimdi bir yapı ile pointer aracılığıyla nasıl oynayacağımıza bakalım.
Örnek:
// Alanları veri tipine göre gruplayarak yeni bir yapı oluşturduk
type Article struct {
id int
title, content, resourceURL string
authorID, categoryID int
}
article := &Article{
0,
"Makale Başlığı",
"Makale İçeriği",
"www.cihanozhan.com",
7,
9,
}
fmt.Println("Başlık: ", (*article).title)
fmt.Println("İçerik: ", (*article).content)
fmt.Println("Resource: ", (*article).resourceURL)
Örnek çıktısı:
Başlık: Makale Başlığı
İçerik: Makale İçeriği
Resource: www.cihanozhan.com
Go dilinde pointer kullanımının yaygın olmasının nedenlerinden bazıları performans ve kaynak yönetimidir.
Yoğun nesneye sahip ve veri işlemleri gerektiren projelerde, gerçekleştirilen her işlem bilgisayar belleğini ciddi
miktarda tüketir. Bunun nedenlerinden biri, kullanılan değer tipindeki nesnelerdir. Her işlem için on binlerce
değer tipinin tekrar tekrar oluşturulması ve bir diğerine kopyalanması nedeniyle hafızada gereksiz bir yük oluşur.
Ancak işaretçi kullanıldığı takdirde, hafızadaki bu nesnelerin kopyaları alınmaz, sadece hafızadaki adresleri
diğer değişkene gönderilerek aynı hafıza adresi ve alanı üzerinde değişiklik yapılması sağlanır.
Uygulama Ödevi : Yukarıdaki yapı ile pointer kullanımı örneğini, pointer kullanmadan tekrar yazın ve sonucu
gözlemleyin.
cihanozhan.com
25. Anonim Alanlar
Go dilinde bir yapı içerisinde alanın adını belirtmeden sadece veri tipini belirterek yapı oluşturmak mümkündür.
Bu yaklaşıma anonim alanlar(anonymous fields) diyoruz.
Örnek:
type Book struct {
string // kitap başlıı
int // kitap fiyatı
}
Versiyon 1:
book := Book{"İleri Seviye T-SQL Programlama", 45}
fmt.Println(book)
Versiyon 2:
var book Book
book.int = 45
book.string = "İleri Seviye T-SQL Programlama"
Örnek çıktısı:
{İleri Seviye T-SQL Programlama 45}
Bu kitabın fiyatını artıralım.
book.int += 1
fmt.Println("Kitap Fiyatı: ", book.int)
Anonim alanlar ilginç bir dil özelliğidir! Veri tipi olarak tanımladığımız int, string ya da diğer veri tipleri
anonim alanlar içerisinde kullanıldığında aynı zamanda bir alan adı olarak kullanılırlar. Bu nedenle bir veri tipini
sadece bir kez tanımlayabilirsiniz.
Yapıcı Metotlar
Bir nesnenin örneğini oluşturma işlemi varsayılan olarak derleyici tarafından yürütülen bir süreçtir. Ancak
programcı olarak istersek bu sürece müdahale ederek kendi nesne örneği oluşturma politikamızı uygulayabiliriz.
Bu işlemi yapabilmemizi sağlayan nesnelere de yapıcı metotlar diyoruz.
Go dili C# ve Java gibi varsayılan olarak yapıcı metotları desteklemez. Yani bunun için özel bir metot tanımlama
yöntemi yoktur. Bu bir eksiklik değildir! Aksine, Go dili tasarımcılarına göre yapıcı metot(constructor) gereksiz
bir özelliktir. Çünkü bu işlemi normal metotları kullanarak zaten yapabilmekteyiz. Tıpkı Go dilinde olduğu
gibi...
Şimdi Go dilindeki yapıcı metot yaklaşımını kavrayabilmek için bir örnek yapalım.
cihanozhan.com
26. Örnek:
type Human struct {
FirstName string
LastName string
Age int
}
// Yapıcı metot olarak kullanılacak metodumuz
func NewHuman(firstName, lastName string) *Human {
human := new(Human)
human.FirstName = firstName
human.LastName = lastName
return human
}
Şimdi bu yapı ve yapıcı metodumuzu kullanalım.
Temel işlemler için belirtmek gerekirse, bir yapının nesne örneğini oluşturmak için yapıcı metotlara ihtiyacımız
yoktur. Ancak profesyonel programlama ve nesne yönelimli programlama yaklaşımları gereği, yapıcı metotların
kullanılması gereken durumların sayısı hiç de az değildir.
Daha önceki yapı oluşturma yöntemlerinde de kullandığımız “ nesne örneğini inşa etme işini derleyiciye
bırakmak” yöntemine tekrar bir göz atalım.
Versiyon 1:
human1 := Human{FirstName: "Cihan"}
human4 := Human{"Cihan", "Özhan", 30}
human5 := Human{FirstName: "Cihan", Age: 30}
fmt.Println(human1.FirstName)
Bu yöntemde nesne örneğinin oluşturulma sürecine aktif olarak müdahale etmedik. Biz sadece başlangıçta
FirstName alanına bir değer ataması yaptık. Bu sayede derleyici arka planda Human nesnesi için bir yapıcı
metot oluşturarak bu nesnenin örneğini oluşturarak bize geri gönderdi. Biz de bu nesne örneğini human1
adındaki değişkenimize atadık.
Versiyon 1 çıktısı:
Cihan
Versiyon 2: new() ile nesne örneği oluşturmak
new() ile nesne örneği oluşturma işlemi, sadece yapılar için değil, daha birçok nesnede kullanılabilen bir
yöntemdir.
Dikkat: NewHuman() isimli yapıcı metot içerisinde de zaten new()’i kullanarak nesnenin yeni bir örneğini
oluşturuyoruz.
human2 := new(Human)
fmt.Println(human2.Age)
Versiyon 2 çıktısı:
0 // Herhangi bir değer ataması yapılmadığı için, sadece integer’ın varsayılan değerini alırız.
cihanozhan.com
27. Versiyon 3: NewHuman() fonksiyonunu ile nesne örneği oluşturmak
Human yapısı için oluşturduğumuz NewHuman() isimli fonksiyonu aslında bir yapıcı metot olması amacıyla
oluşturduk. Bu metodun kullanımının diğer Go metotlarından herhangi bir farkı yoktur.
human3 := NewHuman("Cihan", "Özhan")
human3.Age = 30
fmt.Println(human3)
Versiyon 3 çıktısı:
&{Cihan Özhan 30}
Yukarıda görüldüğü gibi, Go dilinde bir yapının nesne örneğini oluşturmanın birçok yöntemi vardır.
İç İçe Yapı Kullanımı
Mantıksal olarak birbiriyle ilişkili olan farklı yapıları birbiri içerisinde bir alan olarak kullanabiliriz. Bu yönteme
iç içe yapı kullanımı denir.
Bu gereksinime bir örnek vermek gerekirse, User adında bir yapı ile kullanıcı verisini yönettiğimizi düşünelim.
Bu kullanıcılara ait ilgi alanlarını da, Interest adında oluşturduğumuz yapı ile yönetiyoruz. Bu durumda, bir
kullanıcının birden fazla ilgi alanı olabileceğine göre, Interest dizisi([]Interest) alan Interests adında bir alanı
User yapı nesnesine ekleyebiliriz.
Şimdi farklı bir senaryo ile iç içe yapı kullanımını inceleyeceğiz.
Örnek:
Bu örnekte kullanılacak Go paketleri: fmt, strconv
Daha sonra oluşturacağımız kullanıcının ödemelerini tutan bir yapı oluşturalım.
type Payment struct {
Salary float64
Bonus float64
}
Payment yapısının nesne örneğini oluşturmak için kullanacağımız yapıcı metodu oluşturalım.
func NewPayment() *Payment {
p := new(Payment)
return p
}
Bu uygulamanın ana nesnesi olmak üzere User yapısını oluşturalım.
type User struct {
ID int
FirstName string
LastName string
UserName string
Age int
Pay *Payment // İç içe struct tanımladık!
cihanozhan.com
28. }
Buraya dikkat! User yapısı içerisinde başka bir Payment yapısını bir alana veri tipi olarak atadık. İşte iç içe
yapı kullanımı bu şekilde tanımlanmaktadır.
User yapı nesnesi için bir yapıcı metot oluşturalım.
func NewUser() *User {
u := new(User)
u.Pay = NewPayment()
return u
}
Uygulamada kullanacağımız yapı ve yapıcı metotları hazırladık. Şimdi bu yapılar ile birlikte kullanacağımız
fonksiyonları oluşturalım.
Kullanıcının ad ve soyadını birleştirerek geriye dönen GetFullName() fonksiyonun:
func (u User) GetFullName() string {
return u.FirstName + " " + u.LastName
}
Kullanıcının kullanıcı adını dönen fonksiyon:
func (u *User) GetUserName() string {
return u.UserName
}
Kullanıcının “maaş + bonus” algoritmasına göre, kullanıcının elde ettiği aylık kazanımımı geri döner.
func (u *User) GetPayment() float64 {
pay := u.Pay.Salary + u.Pay.Bonus
return pay
}
Şu ana kadar kullanacağımız genel uygulama yapısı hazır. Şimdi bu uygulamayı main() metodu içerisinde
kullanarak inceleyelim.
Versiyon 1:
fmt.Println("Kullanıcı oluşturma v1")
u1 := &User{
ID: 1,
FirstName: "Cihan",
LastName: "Özhan",
UserName: "CihanOzhan",
Age: 30,
Pay: &Payment{
Salary: 2550,
Bonus: 700,
},
cihanozhan.com
29. }
fmt.Println(u1.Pay)
fmt.Println(u1.GetUserName())
fmt.Println(u1.GetFullName())
fmt.Println("Maaş: " + strconv.FormatFloat(u1.GetPayment(), 'g', -1, 64))
// Not : Maaşı gösterebilmek için float64 veri tipini string'e dönüştürdük.
Versiyon 1 çıktısı:
Kullanıcı oluşturma v1
&{2550 700}
CihanOzhan
Cihan Özhan
Maaş : 3250
Versiyon 1 ile sık kullanılan bir yöntemi inceledik. Bu kodlama tarzını profesyonel Go uygulamalarında sık sık
görebilirsiniz.
Şimdi de farklı bir modelle aynı işlemleri gerçekleştirelim.
Versiyon 2:
fmt.Println("Kullanıcı oluşturma v2")
u2 := NewUser()
u2.FirstName = "Cihan"
u2.LastName = "Özhan"
u2.Age = 30
u2.UserName = "Gopher"
Versiyon 2 için Payment nesnesini oluşturma yöntemi 1:
u2.Pay.Salary = 5600
u2.Pay.Bonus = 580
Versiyon 2 için Payment nesnesini oluşturma yöntemi 2:
u2.Pay = &Payment{Salary: 5600, Bonus: 580}
Ve artık hazır olan u2 nesne örneğini kullanabiliriz.
fmt.Println(u2.Pay)
fmt.Println(u2.GetUserName())
fmt.Println(u2.GetFullName())
fmt.Println("Maaş : " + strconv.FormatFloat(u2.GetPayment(), 'g', -1, 64))
// Not : Maaşı gösterebilmek için float64 veri tipini string'e dönüştürdük.
cihanozhan.com